乐趣区

Vue组件之间通信的七种方式

使用 Vue 也有很长一段时间, 但是一直以来都没对其组件之间的通信做一个总结, 这次就借此总结一下。
父子组件之间的通信
1)props 和 $emit
父组件通过 props 将数据下发给 props, 子组件通过 $emit 来触发自定义事件来通知父组件进行相应的操作
具体代码如下:
“`
// 父组件
<template>
<div>
<h3>props 和 $emit</h3>
<Children v-on:changeMsg=”changeMsg” :msg=”msg”/>
</div>
</template>

<script>
import Children from ‘./children’;
export default {
data() {
return {
msg: ‘ 传递的值 ’
}
},
components: {
Children
},
methods: {
changeMsg(val) {
this.msg = val;
}
}
}
</script>

// 子组件
<template>
<div>
<h3 @click=”notify”>{{msg}}</h3>
</div>
</template>

<script>
export default {
data(){
return {

}
},
props: [‘msg’],
methods: {
notify() {
this.$emit(‘changeMsg’, ‘ 修改后的 ’);
}
}
}
</script>
“`
2)vm.$parent 和 vm.$children
vm.$parent: 父实例, 如果当前实例有的话
vm.$children: 获取当前实例的直接直接子组件, 需要注意的是 $children 并不保证顺序, 也不是响应式的
具体代码如下:
“`
// 父组件的代码
<template>
<div>
<h3>{{title}}</h3>
<button @click=”amend”> 在父组件中修改子组件的标题 </button>
<Children />
</div>
</template>

<script>
import Children from ‘./children.vue’;
export default {
data() {
return {
title: ‘ 父组件 ’
}
},
components: {
Children
},
methods: {
amend() {
this.$children[0].title = ‘ 修改后的子组件标题 ’;
}
}
}
</script>
// 子组件的代码
<template>
<div>
<h3>{{title}}</h3>
<button @click=”amend”> 在子组件中修改父组件的标题 </button>
</div>
</template>

<script>
export default {
data() {
return {
title: ‘ 子组件 ’
}
},
methods: {
amend() {
this.$parent.title = ‘ 修改后的父组件标题 ’;
}
}
}
</script>
“`
3) 自定义事件的 v -model
https://cn.vuejs.org/v2/guide/components-custom-events.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E7%9A%84-v-model
具体代码如下:
“`
// 父组件
<template>
<div>
标题:<input type=”text” v-model=”mymessage”><br />
<Children v-model=”mymessage” />
</div>
</template>

<script>
import Children from ‘./children.vue’;
export default {
data() {
return {
mymessage: ‘ 名字 ’,
}
},
components: {
Children
}
}
</script>
// 子组件
<template>
<div>
<input type=”text” :value=”mymessage” @input=”changeValue”>
</div>
</template>

<script>
export default {
model: {
prop: ‘mymessage’,
event: ‘input’
},
props: [‘mymessage’],
methods: {
changeValue(event){
this.$emit(‘input’, event.target.value);
}
}
}
</script>
“`
祖先组件和其子孙组件通信
1)provide/inject
provide/inject, 允许一个祖先组件向其所有子孙后代注入一个依赖, 不论组件层次有多深, 并在起上下文关系成立的时间里始终生效
https://cn.vuejs.org/v2/api/#provide-inject
具体代码如下:
“`
// 父组件
<template>
<div>
<h3>{{title}}</h3>
<Children />
</div>
</template>

<script>
import Children from ‘./children.vue’;
export default {
data() {
return {
title: ‘ 父组件的标题 ’
}
},
provide() {
return {
updateTitle: this.updateTitle
}
},
methods: {
updateTitle(title) {
this.title = title;
}
},
components: {
Children
}
}
</script>
// 子组件
<template>
<div>
<button @click=”changeAttr”> 修改父组件的属性 </button>
<Grandson />
</div>
</template>

<script>
import Grandson from ‘./grandson.vue’;
export default {
data() {
return {

}
},
inject: [‘updateTitle’],
methods: {
changeAttr() {
this.updateTitle(‘ 子组件修改标题 ’);
}
},
components: {
Grandson
}
}
</script>
// 孙组件
<template>
<div>
<button @click=”changeAttr”> 修改祖先组件的属性 </button>
</div>
</template>

<script>
export default {
inject: [‘updateTitle’],
methods: {
changeAttr() {
this.updateTitle(‘ 孙组件修改标题 ’);
}
}
}
</script>
“`
2)$attrs 和 $listeners
组件 A 下面有一个组件 B, 组件 B 下面有一个组件 C, 如果想将组件 A 的数据和自定义事件传递给组件 C, 就可以使用 $attrs 和 $listeners。
vm.$attrs: 当一个组件没有声明任何 prop 时 (没有在 props 声明属性),这里会包含所有父作用域的绑定,并且可以通过 v-bind=”$attrs” 传入内部组件
vm.$listeners: 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件。
https://cn.vuejs.org/v2/api/#vm-attrs
具体代码如下:
“`
// 父组件
<template>
<div>
<Children :msg=”msg” v-on:changeMsg=”changeMsg”/>
</div>
</template>

<script>
import Children from ‘./children’;
export default {
data() {
return {
msg: ‘ 下发数据 ’,
test: ‘123’
}
},
components: {
Children
},
methods: {
changeMsg() {
this.msg = ‘ 修改后的数据 ’;
}
}
}
</script>
// 子组件
<template>
<div>
<Grandson v-bind=”$attrs” v-on=”$listeners”/>
</div>
</template>

<script>
import Grandson from ‘./grandson’;
export default {
components: {
Grandson
}
}
</script>
// 孙组件
“`
<template>
<div>
<h3>{{$attrs.msg}}</h3>
<button @click=”change”> 修改数据 </button>
</div>
</template>

<script>
export default {
data() {
return {

}
},
methods: {
change() {
this.$emit(‘changeMsg’)
}
}
}
</script>

“`
“`
非父子组件之间的通信
通过中央事件总线来进行通信
通过新建一个 Vue 事件的 bus 对象, 然后通过 bus.$emit 来触发事件,bus.$on 监听触发的事件。使用中央事件总线时, 需要在手动清除它, 不然它会一直存在, 原本只执行一次的操作, 将会执行多次。
具体代码如下:
“`
// 父组件
<template>
<div>
<One />
<Two />
</div>
</template>

<script>
import One from ‘./one.vue’;
import Two from ‘./two.vue’;
export default {
data() {
return {

}
},
components: {
One,
Two
}
}
</script>
// one 组件
<template>
<div>
<h3> 第一个组件 </h3>
<button @click=”add”> 增加数量 </button>
</div>
</template>

<script>
import {BUS} from ‘./index.js’;
export default {
data() {
return {

}
},
methods: {
add() {
BUS.$emit(‘add’);
}
},
beforeDestory() {
BUS.$off(‘add’);
}
}
</script>
// two 组件
<template>
<div>
<h3> 第二个组件 </h3>
<h3> 数量: {{num}}</h3>

</div>
</template>

<script>
import {BUS} from ‘./index.js’;
export default {
data() {
return {
num: 1
}
},
mounted() {
BUS.$on(‘add’, () => {
this.num += 1;
})
},
beforeDestroy() {
BUS.$off(‘add’);
}
}
</script>
// index.js 创建的 bus
import Vue from ‘vue’;
export const BUS = new Vue({
})
“`
通过 vuex 来进行数据管理, 具体内容见 vuex 官网
如果有什么不对的地方, 或者还有什么方法我没有写到, 希望大家可以提出来, 谢谢。

退出移动版