一文读懂VUE组件间传值问题

Vue组件间通信包括:父子组件间通信,兄弟组件间通信以及模块之间通信等。Vue是数据驱动视图更新的框架, 所以对于Vue来说组件间的数据通信非常重要。

父子组件间通信

Vue实现组件间通信有很多方式,今天我来给大家讲解一下父子组件间通信:props和$emit。

父组件通过props的方式向子组件传递数据,而通过$emit子组件可以向父组件通信。

本文通过一个实例实现:子组件是一张图片,图片相关信息包括宽度、高度、路径等由父组件传递过来的,点击子组件的图片,调用父组件的方法,将信息告诉给父组件。

父组件向子组件传值:props

props是响应式的,可以做数据绑定。

下面通过实例说明父组件如何向子组件传递数据:在子组件Children.vue中如何获取父组件Father.vue中的数据。

在src/components/文件夹下建一个父组件Father.vue和子组件Children.vue。

在Children.vue中创建props,用于接收父组件传递的值。

<img :src="imgSrc" :width="imgWidth" :height="imgHeight" :alt="title" @click="doSomething">

Children.vue子组件中的,可以直接用this.imgWidth形式获取到父组件传递过来的值。

export default {
    name: 'children',
    props:{
        imgWidth: {
            type: Number,
            default: 300
        },
        imgHeight: {
            type: Number
        },
        title: {
            type: String,
            default: ''
        },
        imgSrc: {
            type: String,
            default: ''
        }
    },
}

根据Vue风格指南中建议的,props 的定义应该尽量详细,至少需要指定其类型。

父组件Father.vue导入子组件:

<hw-child :img-src="imgSrc" :img-width="300" :img-height="imgHeight" title="静态文字" @onEmitFunction="emitFuction"></hw-child>

如果传给子组件的是一个变量或者数字,则需要前面加上:(v-bind的缩写)绑定。

我们使用@onEmitFunction="emitFuction"监听子组件触发的自定义事件。

import Child from './Children.vue'

export default {
    components: {
        hwChild: Child,
    },
    data() {
        return {
            imgHeight: 300,
            imgHeight: 300,
            imgSrc: '//img1.shikee.com/try/2016/06/23/15395220917905380014.jpg'
        }
    },
    methods: {
        emitFuction(val) {
            console.log(val);
            alert('获取子组件参数:'+ val);
        }
    }
}

这时,运行可以看到父组件已经加载子组件,并且成功加载了一张美女图片。

注意:props只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 props 只读,不可被修改,所有修改都会失效并警告。

子组件向父组件传值: $emit

$emit绑定一个自定义事件, 当这个语句被执行时, 就会将参数arg传递给父组件,父组件通过v-on监听并接收参数。

在方法函数中使用$emit来触发一个自定义事件,并传递一个参数,这个参数就是子组件要传递给父组件的值。

我们在Children.vue中绑定了click事件,通过单击来触发方法函数:doSomething()

methods: {
        doSomething() {
            // todo
            const val = '子组件参数xxxx';
            this.$emit('onEmitFunction', val);
        }
    }

很显然,此处使用$emit调用了父组件的方法:onEmitFunction,并且通过此方法传递了参数val给父组件。

再回到父组件Father.vue中,我们使用@onEmitFunction="emitFuction"监听子组件触发的自定义事件onEmitFunction。

在父组件Father.vue中,添加自定义方法函数:

methods: {
        emitFuction(val) {
            console.log(val);
            alert('获取子组件参数:'+ val);
        }
    }

现在运行一下,点击子组件中的图片,弹出提示,获取到了子组件中的数据。

父子组件间通信的方式:$refs

Vue官方文档上说了 ref 被用来给元素或子组件注册引用信息。就是绑定在普通元素上,则获取到这个DOM元素,若是绑定在组件上,则获取到的是这个组件的Vue实例vm。

也就是说可以通过$refs直接调用组件的方法或访问数据, 我们看一个ref来访问组件的例子:

子组件 Com.vue

<template>
    <div>
        <p>{
   
   {str}}</p>
        <p>{
   
   {messageA}}</p>
        <p>获取父组件的值: {
   
   {parentVal}}</p>
    </div>
</template>

<script>
export default {
  data () {
    return {
      str: '睡懒觉中...',
      messageA: 'Helloweba'
    }
  },
  computed: {
    parentVal() {
        return this.$parent.msg;
    }
  },
  methods: {
    doSomething () {
        //to do
        this.str = '是,马上就起床!'
        console.log('hello');
    }
  }
}
</script>

父组件main.vue

<template>
    <div>
        <div class="main">
            <h3>父组件</h3>
            <p><button @click="wakeup">呼唤子组件</button></p>
            <hw-com ref="com" style="width: 95%; border: 1px dashed #ccc"></hw-com>
        </div>
    </div>
</template>

<script>
import Com from './Com.vue'

export default {
    components: {
        hwCom: Com,
    },
    data() {
        return {
            msg: 'Welcome!'
        }
    },
    mounted() {
        const com = this.$refs.com;
        console.log(com.str);  //睡懒觉中...
        com.doSomething(); //是,马上就起床!
    },
    created() {
        
    },
    methods: {
        wakeup() {
            
        }
    }
}
</script>

我们要在父组件Main.vue中访问子组件Com.vue中的doSomething方法,可以直接在mounted中使用this.$refs.com.doSomething();就能做到。值得注意的是,Vue更新数据是异步的,我们需要等到DOM更新完成,所以使用$ref进行DOM操作的时候,需要将调用代码放在mounted中,或者放在created$nextTick(() => {})中:


    created() {
        this.$nextTick(() => {
             const com = this.$refs.com;
             com.doSomething();
        });

    },

此外,$refs 也不是响应式的,因此不应该试图用它在模板中做数据绑定。

$children和$parent

Vue官方文档上说了,使用$parent$children也可以访问组件的实例,拿到实例代表什么?代表可以访问此组件的所有方法和data。

在父组件Main.vue中,点击按钮触发wakeup()方法,通过$children来访问子组件中的messageA属性。


    methods: {
        wakeup() {
            this.$children[0].messageA = 'HIII';
            this.msg = 'Hi hi hi...';
        }
    }

而在子组件Com.vue中,可以使用$parent来访问父组件中的数据。


computed: {
    parentVal() {
        return this.$parent.msg;
    }
},

父组件访问子组件使用$refs即可,对于$children和$parent最好不要使用了。

兄弟组件间通信

eventBus又称为事件总线

在vue中可以使用它来作为沟通桥梁, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所有组件都可以通知其他组件。

那么,在Vue的项目中怎么使用eventBus来实现组件之间的数据通信呢?具体通过下面几个步骤:

1. 初始化

首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它。

我们在src/components/目录下新建文件bus.js。

import Vue from 'vue'
export default new Vue()

2. 发送事件

假设你有两个兄弟组件: ComA和ComB,ComA发送消息给ComB。

ComA这样:

<template>
    <div>
        <button @click="sendMsg">给组件B发送消息</button>  
    </div>
</template>

<script>
import bus from './bus'

export default {
    name: 'comA',
    data () {
        return {
            
        }
    },
    
    methods: {
        sendMsg() {
            bus.$emit('fromA', {
                phone: 13800138000
            })
        }
    }
}
</script>

很显然,ComA中使用bus.$emit(事件名,数据);向事件中心注册发送事件。

3. 接收事件

ComB接受ComA发送过来的消息。

<template>
    <div>
        <p>{
   
   {fromA}}</p>
    </div>
</template>

<script>
import bus from './bus'

export default {
    name: 'comB',
    data () {
        return {
            fromA: '',
        }
    },
    mounted() {
        bus.$on('fromA', param => {
            this.fromA = param.phone;
        })
    }
}
</script>

于是,当ComA发送了一个手机号码phone给ComB时,comB就会接收并显示。

父组件

在父组件中调用ComA和ComB两个兄弟组件。

<template>
  <div>
    <comA></comA>
    <comB></comB>
  </div>
</template>

<script>
import ComA from './ComA.vue'
import ComB from './ComB.vue'

export default {
    components: {
       ComA,
       ComB
    },
}
</script>

注意,eventBus也有不方便之处, 当项目较大,维护起来就相当困难,这时我们应该用到Vuex状态管理来解决。本站后面有文章给大家讲解vuex组件状态管理。 

猜你喜欢

转载自blog.csdn.net/qq_28471389/article/details/113176214