vue项目中,组件间的通信是最常用到的,也是面试必问的问题之一。
组件通信可以分为几种类型:
1、父子通信
1.1 父传子
1.2 子传父
2、跨级传递
2.1祖父传孙
3.1孙传祖父
3、同级组件间通信
首先说一下通用的方式,即不管哪种场景都在功能上可以实现,撇开具体场景的适合程度,其实也就是全局的通信方式。
一、vue bus 以vue实例为总线,传递数据
新建bus.js和busA.vue、busB.vue:
bus.js
import Vue from "vue"
const Bus = new Vue();
export default Bus;
在main.js引入,挂载到全局上去:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import Bus from "@/utils/bus";
Vue.config.productionTip = false;
Vue.prototype.bus = Bus;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
busA.vue:
busB.vue:
这样就实现了兄弟组件之间的数据传递,当然也适合所有类型的组件通信。
二、vuex 官方提供的状态管理器,统一管理状态,可参考官方文档。
一、父子通信
1、父传子:props
子传父:$emit
这两种方式都是最常用也是最简单的,可参考官方文档
2、通过实例通信:
$children
$parent
获取节点实例,然后访问实例下的数据或方法
3、父组件里给子组件设置ref属性,通过this.$refs.name访问子组件实例
二、隔代传递
利用组件的name属性作为标识,通过递归、遍历找到name对应的实例并返回,只要拿到了实例,那就可以随意访问实例下的数据和方法了。
1、向上查找最近指定节点
export const findComponentUpword = (context,componentName) => {
let parent = context.$parent;
let name = parent.$options.name;
while(parent && (!name || [componentName].indexOf(name) < 0) {
parent = parent.$parent;
if(parent) {
name = parent.$options.name;
}
}
return parent || null;
}
组件中调用(父组件一定要有具体的name属性才行,不然找不到):
import {findComponentUpward} from "@/utils"
、、、、
、、、、
let fatherComponent = findComponentUpward(this,"FatherName"); // 父组件名称
2、向上查找所有指定节点
export const findComponentsUpward = (context,componentName) => {
let parents = [];
let parent = context.$parent;
let name = parent.$options.name;
if(parent) {
if(name === componentName) {
parents.push(parent);
}
return parents.concat(findComponentsUpward(parent,componentName));
}else {
return [];
}
}
组件中调用:
import {findComponentsUpward} from "@/utils"
、、、、
、、、、
let fatherComponent = findComponentsUpward(this,"FatherName"); // 父组件名称, 返回匹配组件的实例数组
3、向下查找最近的指定节点
export const findComponentDownward = (context,componentName) => {
let children = context.$children;
let child = null;
if(children.length) {
for(const childItem in children) {
const name = childItem.$options.name;
if(name === componentName) {
child = childItem;
break;
}else {
child = findComponentDownward(childItem,componentName);
if(child) {break}
}
}
}
return child;
}
4、向下查找所有的指定节点
export const findComponentsDownwards = (context,componentName) => {
return context.$children.reduce((components, child) => {
if(child.$options.name === componentName) {
components.push(child);
}
const findChildren = findComponentsDownwards(child,componentName);
return [...components,...findChildren];
},[])
}
5、provide、inject方式
vue的api原生提供的方法,在父组件向下注入一个provide,不管子组件嵌套有多深,都可以通过inject获取到
父组件:
子组件:
有了这些组件通信方式,再复杂的业务需求也能得到满足了