vue组件间通信
父组件向子组件通信
vue中父组件向子组件通信是通过props
属性实现的,用户需要在子组件的vue对象中设置props
属性。在使用这个属性的时候,应该避免在子组件中修改props的值,vue是不建议这么做的
<!-- 父组件 -->
<template>
<div class="container">
<button class="btn" @click="sendMsg">给子组件发送消息</button>
<div class="words">
<child :parentMessage="parentMessage"></child>
</div>
</div>
</template>
<script>
import Child from './Child';
export default {
name: 'Parent',
data() {
return {
parentMessage: ''
}
},
components: {
Child
},
methods: {
sendMsg() {
this.parentMessage = '父组件发来一条消息'
}
}
}
</script>
<!-- 子组件 -->
<template>
<div class="container">
<div class="words" v-if="parentMessage">{{ parentMessage }}</div>
</div>
</template>
<script>
export default {
name: 'Child',
props: ['parentMessage'],
}
</script>
子组件向父组件通信
1.emit事件触发的方式
准确来说,在这种方法中,子组件没有向父组件传递数据,只是子组件触发父组件监听的事件。我们可以在子组件中自定义事件,然后在父组件中监听子组件发过来的事件
<!-- 子组件 -->
<template>
<div class="container">
<button @click="sendMsg">给父组件发送消息</button>
</div>
</template>
<script>
export default {
name: 'Child',
props: ['parentMessage'],
data() {
return {
childMessage: ''
}
},
methods: {
sendMsg() {
this.$emit('finish')
}
}
}
</script>
<!-- 父组件 -->
<template>
<div class="container">
<child @finish="receive"></child>
<p>{{ childMessage }}</p>
</div>
</template>
<script>
import Child from './Child';
export default {
name: 'Parent',
data() {
return {
childMessage: ''
}
},
components: {
Child
},
methods: {
receive() {
this.childMessage = '子组件呼叫'
}
}
}
</script>
2.通过回调函数实现
前面我们用props属性来实现父组件向子组件通信,实际上,我们也可以使用props来实现子组件向父组件的通信
<!-- 父组件 -->
<template>
<div class="container">
<child @finish="receive" :son="son"></child>
</div>
</template>
<script>
import Child from './Child';
export default {
name: 'Parent',
data() {
return this.childMessage = ''
},
components: {
Child
},
methods: {
receive() {
this.childMessage = '子组件呼叫'
},
son() {
this.receive()
}
}
}
</script>
<!-- 子组件 -->
<template>
<div class="container">
<button @click="son">给父组件发送消息</button>
</div>
</template>
<script>
export default {
name: 'Child',
props: ['son']
}
</script>
3.通过$refs实现
父组件可以通过$refs来获取子组件的属性和方法,但是$refs不是响应式的,因此不要视图用它在模板中做数据绑定。另外,vue的数据更新是异步的,我们需要等待DOM更新完成后才进行DOM元素数据读取。那么,按照这个思路,我们在父组件中获取$refs的值时需要放在created的$nextTick或mounted中
<!-- 父组件 -->
<template>
<child ref="childName"></child>
</template>
<script>
// ...省略一些内容
created() {
this.$nextTick(() => {
this.childMessage += this.$refs.childName.$data.childData;
this.childMessage += ' - ' + this.$refs.childName.childRef();
})
},
/*
mounted() {
this.childMessage = this.$refs.childName.$data.childData;
this.childMessage += " - " + this.$refs.childName.childRef();
}*/
</script>
<!-- 子组件 -->
<script>
// ... 省略一些内容
data() {
return {
childData: "子组件通过ref向父组件通信1"
}
},
methods: {
childRef() {
return "子组件通过ref向父组件通信2"
}
}
</script>
兄弟组件通信
1.通过一个共同的父组件进行通信
<!-- 父组件 -->
<template>
<div class="container">
<brother-one :messageOne="messageone" @brotheroneSaid="pMessageTwo($event)"></brother-one>
<brother-two :messageTwo="messagetwo" @brothertwoSaid="pMessageOne($event)"></brother-two>
</div>
</template>
<script>
import BrotherOne from './BrotherOne';
import BrotherTwo fro './BrotherTwo';
export default {
name: 'Parent',
data() {
messageone: '',
messagetwo: ''
},
components: {
BrotherOne,
BrotherTwo
},
methods: {
pMessageOne(message) {
this.messageone = message
},
pMessageTwo(message) {
this.messagetwo = message
},
}
}
</script>
<!-- 子组件 -->
<template>
<div class="container">
<button @click="messageTwo">给BrotherTwo发消息</button>
<p>{{ messageOne }}</p>
</div>
</template>
<script>
export default {
name: 'BrotherOne',
props: ['messageOne'],
methods: {
messageTwo() {
this.$emit('brotheroneSaid', '来自BrotherOne的消息')
}
}
}
</script>
<template>
<div class="container">
<button @click="messageOne">给BrotherOne发消息</button>
<p>{{ messageTwo }}</p>
</div>
</template>
<script>
export default {
name: 'BrotherTwo',
props: ['messageTwo'],
methods: {
messageOne() {
this.$emit('brothertwoSaid', '来自BrotherTwo的消息')
}
}
}
</script>
其实这种方式实现的原理类似与前面所说的子组件向父组件使用emit通信的方式,先对某个子组件设置一个click事件:
<button @click="messageTwo">给BrotherTwo发消息</button>
当点击按钮时会触发messageTwo
方法,在这个方法中用emit触发父组件监听的brotheroneSaid
事件,一旦触发了父组件的brotheroneSaid
事件,那么就会触发其绑定的pMessageTwo
方法
2.通过EventBus实现
前面的那个方法在子组件不多的情况下可用,但是如果组件数量较多,那么代码就会很复杂,也容易绕晕,所以我们需要引入EventBus
我们创建一个新文件eventbus.js
,内容如下:
import Vue from 'vue';
export default new Vue();
可以看出实际上,它就是创建一个全新的vue实例。
然后我们在组件中引入同一个文件,假如我们要在生命周期钩子中做监听:
<!-- 组件1 -->
import eventbus from 'eventbus.js';
data() {
message: ''
},
created() {
eventbus.$on('getMsg', this.getMsg);
},
beforeDestory() {
eventbus.$off('getMsg', this.getMsg);
},
methods: {
getMsg(param) {
this.message = params
}
}
<!-- 组件2 -->
import eventbus from 'eventbus.js';
methods: {
doSomething() {
eventbus.$emit('getMsg', 'demo');
}
}
实际上,前面提到的兄弟组件间通信的方法都不适合用于数据量很大的操作。更优的方案应该是使用vuex
如果你想让上面的demo在线运行,请点击: https://codesandbox.io/s/yrkk2rx1v
参考
W3plus - Vue组件通讯
W3plus - Vue 2.0学习笔记:事件总线(EventBus)
W3plus - Vue 2.0学习笔记:不同场景下组件间的数据通讯