目录
前言
一、props 和 $emit
1、一般的通信
2、子组件更新父组件的变量
二、$attrs 和 $listeners
三、eventBus——$emit 和 $on
四、provide 和 inject(跨组件通信)
1、认识 provide 和 inject
2、provide 和 inject 的使用
(1)、传递普通的数据
(2)、传递异步的数据
五、使用 vue-ref 插件结合 provide 和 inject 获取组件的实例
六、v-model
七、$parent、$children 和 $refs
1、$children 和 $rfes
2、$parent(不建议使用)
3、案例
八、vuex 处理组件之间的数据交互
参考:vue组件之间8种组件通信方式总结
vue 组件之间的通信方式大概有 9 种:
父传子——props
子传父——$emit
Vue.component("child", {
data() {
return {
mymessage: this.message,
};
},
template: `
`,
props: ["message"], //得到父组件传递过来的数据
methods: {
passData(val) {
//触发父组件中的事件
this.$emit("getChildData", val);
},
},
});
Vue.component("parent", {
template: `
this is parent compoent!
`,
data() {
return {
message: "hello",
};
},
methods: {
//执行子组件触发的事件
getChildData(val) {
console.log(val);
},
},
});
var app = new Vue({
el: "#app",
template: `
`,
});
上述代码中,父组件传递了message数据给子组件,并且通过v-on绑定了一个getChildData事件来监听子组件的触发事件;子组件通过props得到相关的message数据,最后通过this.$emit触发了getChildData事件。
假设有这么一个场景:私人订制一只宠物。父组件是具有定制宠物的给用户的功能,子组件具有决定定制什么宠物的功能。那么此时,子组件在调用父组件的定制宠物的给用户的功能时,就需要给选定一种宠物,这就需要传递第二个参数了。
vue 在子组件中更新父组件中传过来的变量——.sync 和 $emit(update:xxx)https://blog.csdn.net/mChales_Liu/article/details/122193214
问题:如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢?
可以借助 $attrs 和 $listeners 来实现 “隔代传值”。
Vue.component("C", {
template: `
`,
methods: {
passCData(val) {
//触发父组件A中的事件
this.$emit("getCData", val);
},
},
});
Vue.component("B", {
data() {
return {
mymessage: this.message,
};
},
template: `
`,
props: ["message"], //得到父组件传递过来的数据
methods: {
passData(val) {
//触发父组件中的事件
this.$emit("getChildData", val);
},
},
});
Vue.component("A", {
template: `
this is parent compoent!
`,
data() {
return {
message: "hello",
messagec: "hello c", //传递给c组件的数据
};
},
methods: {
getChildData(val) {
console.log("这是来自B组件的数据");
},
//执行C子组件触发的事件
getCData(val) {
console.log("这是来自C组件的数据:" + val);
},
},
});
var app = new Vue({
el: "#app",
template: `
`,
});
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
$emit 和 $on 的实现:新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。
Vue.component("brother1", {
data() {
return {
mymessage: "hello brother1",
};
},
template: `
this is brother1 compoent!
`,
methods: {
passData(val) {
//触发全局事件globalEvent
bus.$emit("globalEvent", val);
},
},
});
Vue.component("brother2", {
template: `
this is brother2 compoent!
brother1传递过来的数据:{{brothermessage}}
`,
data() {
return {
mymessage: "hello brother2",
brothermessage: "",
};
},
mounted() {
//绑定全局事件globalEvent
bus.$on("globalEvent", (val) => {
this.brothermessage = val;
});
},
});
//中央事件总线
var bus = new Vue();
var app = new Vue({
el: "#app",
template: `
`,
});
provide 和 inject 是成对出现的。在上层组件中通过 provide 来提供变量,然后在下层组件中通过 inject 来注入变量。用于父组件向子孙组件传递数据。
provide 选项可以是:
inject 选项可以是:
provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
父组件:
子组件:
{{ msg }}
父组件:
子组件:
{{ newStatus }}
【注意】小型状态管理,可以使用 provide/inject。大型状态管理,建议使用 vuex。
【扩展】
vue中的provide和inject
vue中provide和inject使用
可以使用 ref 来获取跨级组件实例。
安装:vue-ref
npm i vue-ref -S
然后,在main.js中写入下面的代码:
import ref from 'vue-ref';
Vue.use(ref, { name: 'getRef' });// 这里之所以重命名,是为了避免与vue预留的v-ref指令冲突
假设,已经创建了vue实例,并且在其中引入了index.vue,或者配置好了vue-router。
// index.vue
子组件:A
// ChildrenA1.vue
A 结点
子组件的子组件:E
// childrenE.vue
E 结点
子组件的子组件:H
H 结点
父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input’,val)自动修改v-model绑定的值。
Vue.component("child", {
props: {
value: String, //v-model会自动传递一个字段为value的prop属性
},
data() {
return {
mymessage: this.value,
};
},
methods: {
changeValue() {
this.$emit("input", this.mymessage); //通过如此调用可以改变父组件上v-model绑定的值
},
},
template: `
`,
});
Vue.component("parent", {
template: `
this is parent compoent!
{{message}}
`,
data() {
return {
message: "hello",
};
},
});
var app = new Vue({
el: "#app",
template: `
`,
});
注意:在组件上使用 v-model
有时候我们需要父组件直接访问子组件、子组件直接访问父组件,或者子组件访问根组件:
this.$children 是一个数组类型,它包含了所有子组件对象,可以通过循环它拿到所有子组件数据。
比如:this.$children[2] 来拿到第三个子组件的数据。
但是这么做有一个问题:比如开发时突然在这三个子组件中又插入了一个子组件(可能相同,也可能不同),这时候 this.$children[2] 就不再是我们需要的了。怎么办呢?使用 $rfes。
$parent 是当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。该属性只读。
不建议使用 $parent,因为它的耦合度很高,容易发生一些错误。
Vue.component("child", {
props: {
value: String, //v-model会自动传递一个字段为value的prop属性
},
data() {
return {
mymessage: this.value,
};
},
methods: {
changeValue() {
this.$parent.message = this.mymessage; //通过如此调用可以改变父组件的值
},
},
template: `
`,
});
Vue.component("parent", {
template: `
this is parent compoent!
`,
methods: {
changeChildValue() {
this.$children[0].mymessage = "hello";
},
},
data() {
return {
message: "hello",
};
},
});
var app = new Vue({
el: "#app",
template: `
`,
});
如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。
详情可参考:Vuex