Vue — 组件通信(三)
最后更新于:2022-04-02 08:08:45
>[success] # 组件通信(三)
~~~
1.了解'$on'与'$emit'
2.根据Vue.js 1.x 的 '$dispatch' 与 '$broadcast' 两方法思路伪造一个,
属于vue.js 2.x 系列同样的方法.其中 '$dispatch'子传父或者孙子传爷爷,
'$broadcast' 则相反,但是只会找到最近的触发
~~~
>[info] ## 了解 '$on'与'$emit'
~~~
1.使用 $on(eventName) 监听事件第二个参数是个方法,
使用 $emit(eventName) 触发事件第二个参数是传值,
这两个方法常见的使用场景就是'bus'
2.要注意 '$on' 监听需要在 mounted 或 created 钩子中来监听。
3.可以参考笔者另一个笔记内容'前端知识 -- 学习整理',这个思路就是设计
模式中的'发布订阅'模式
~~~
>[danger] ##### 不是只有bus 才能用
~~~
1.$on 监听了自己触发的自定义事件 test,因为有时不确定何时会触发事件,
一般会在 mounted 或 created 钩子中来监听。
~~~
* 自己触发自己的$emit 和 $on,下面写法多此一举建议直接handleEmitEvent触发alter
~~~
~~~
* 运行效果
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/e0e510d7ef4262335aca864d09748cc2_649x190.png)
>[info] ## 自定义 dispatch 和 broadcast 方法 思路
~~~
1.在vue1.x 中'$dispatch' 是子孙组件向父爷组件传递,'broadcast '则相反,
但是只会找到最近的触发
2.两者都是使用'$on' 触发
~~~
>[danger] ##### 定义前看一下vue1.x版本使用
~~~
1.在这里 还要强调说明监听的'$on'要在 mounted 或 created 钩子中来监听。
~~~
* 在子组件定义
~~~
~~~
* 在父组件中使用
~~~
~~~
>[danger] ##### 封装思路
~~~
1.通过上面1.x案例可以看出来,大体上需要两个参数一个是触发的事件名字,一个是传
递的参数,但是我们自定义的需要使用一个标记参数,来找到我们需要匹配的组件,如何
找这里就利用创建组件的使用name属性如下图
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/07b1a1d66d13d37193f498972742ea8a_539x151.png)
>[info] ## 正式封装
~~~
1.思路其实就是利用 '$on' 和 '$emit' 配合,通过我们自己写的这个方法,让对应
要调用的父组件或者子组件,this指向他本身,这样形成给其自身加入对应的方法,
但可以有子组件或父组件的传值
2.首先明确一点'$emit' 和 '$on' 是典型的发布的订阅模式,'$on'通过订阅的方式,来接受'$emit'
发布的内容,当然他的发布和订阅 必须是同一个'this',因此利用vue自带的'$parent' 和'$children'
从父组件开始找也好,从子组件开始找也好,原理就是层级向上找让彼此可以发布订阅在一起
~~~
代码参考[iView](https://link.juejin.im/?target=https%3A%2F%2Fgithub.com%2Fiview%2Fiview%2Fblob%2F2.0%2Fsrc%2Fmixins%2Femitter.js)。
>[danger] ##### 从子组件传递给父组件甚至爷爷组件
~~~
1.获取当前组件的'parent',因为刚才构想过,我们需要传递三个参数,其中一个参数要匹配
的目标组件名字,因此逻辑就是去找'parent' 和要匹配的名字是否一致,找到符合的'parent'
给这个父组件添加'$emit'事件,在这个父组件中使用'$on' 去触发
~~~
~~~
// 子传父,孙子传爷爷或者爸爸
/*
* @params:componentName 对应组件名 ,eventName 事件名称,params 函数参数
* */
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root;
let name = parent.$options.name;
console.log(this.$options)
console.log(this.$options.name)
// 递归一层一层找
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
// 有父组件名称 在去找组件name,如果没有了 就不用特意去找
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
parent.$emit(parent, [eventName].concat(params));
// parent.$emit(eventName,params);
}
},
~~~
>[danger] ##### 从爷爷组件给孙子组件,父传子
~~~
1.思路就找每一个children,找到是否 有和名字匹配的并且绑上$emit()事件
~~~
~~~
function broadcast(componentName, eventName, params) {
this.$children.forEach(child => {
const name = child.$options.name;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
~~~
>[danger] ##### 将所有代码放到mixins进行存储使用(最后的封装)
~~~
function broadcast(componentName, eventName, params) {
// 当前的this 指向是在methods broadcast 中被改变了
// 因此现在的this 是每一个组件的this
this.$children.forEach(child => {
const name = child.$options.name;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
// 递归 更改新的this,获取新的组件中的children,也就是更新成当前父组件的this
broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
export default {
methods: {
// 子传父,孙子传爷爷或者爸爸
/*
* @params:componentName 对应组件名 ,eventName 事件名称,params 函数参数
* */
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root;
let name = parent.$options.name;
console.log(this.$options)
console.log(this.$options.name)
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
// 有父组件名称 在去找组件name,如果没有了 就不用特意去找
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
// parent.$emit(eventName,params);
}
},
broadcast(componentName, eventName, params) {
// 当前this 也就是其中的父组件 有了broadcast方法
broadcast.call(this, componentName, eventName, params);
}
}
};
~~~
>[danger] ##### 使用
~~~
1.要注意'$on' 要放到mounted 或 created 去使用
~~~
* 父组件
~~~
~~~
* 子组件
~~~
~~~
';