当一个对象中的数据被多个对象所依赖,并且当被依赖发生变化的时候,会通知一个调度中心,并由调度中心通知所有的依赖项。我们称这种模式为订阅发布者模式,被依赖的对象我们称之为发布者,依赖项我们称之为订阅者。
下面是vue官网双向绑定原理的图,他是通过Object.defineProperty
或者new Proxy
去监听对象数据变化,对象相当于一个发布者(publisher),当监听到对象改变后对象的setter
就会发送消息通知订阅者(watcher),订阅者收到消息后通知对DOM文本进行update
操作。
observe() {
const handler = {
get: (target,propkey) => {
return target[propkey];
},
set :(target,propkey,value) => {
if(target[propkey] !== value) {
target[propkey] = value;
this.watcher(propkey);
}
return true;
}
};
this.data = new Proxy(this.data,handler);
}
watcher(key) {
if(this.modelObj[key]) {
this.modelObj[key].forEach((node) => {
this.setModelData(key,node);
})
}
for(const node of this.nodeArr) {
this.changeData(node);
}
}
上面代码是用Proxy实现一个双向绑定的部分代码,从代码片段中可以看到observer作为一个发布者,它可以同时被多个变量订阅,当监听到数据发生改变时,调用set方法通知watcher(订阅者)去改变node节点和值。
<input v-model="name" />
同理,上述代码描述的是,当我们给input
输入框作为一个发布者,watcher
作为订阅者。当用户输入数据时,发布者(input) 向订阅者(watcher) 发送改变信息的通知,watcher
收到通知后进行值得修改和node节点数据更改,这就是vue通过发布订阅模式实现的数据双向绑定。
在vue中的数据通信,非常常见的有父子组件通信,兄弟组件通信。父子组件通信很简单,父组件会通过 props
向下传递给子组件,子组件通过 $emit事件告诉给父组件。跨多级组件间通信可以用 provide
和 inject
,但是它存在数据不好实时更新的问题。像一个负责页面多处弹窗展现,每次只显示一个弹窗的场景,用Eventbus
- Vue事件总线更适合,当然对于不同视图公用数据、更新数据的,业务更复杂的场景,建议使用 Vuex
来处理组件之间的数据通信。这次我们先来说说 EventBus
通信的使用和实现原理。
EventBus
事件总线,不仅仅是 Vue 中独有的,像安卓、后端等都存在这个概念以及它的大量使用。毕竟这是一种通用的发布订阅设计模式和解决方案。在 Vue 中,使用 EventBus
来作为所有组件共用的事件中心,可以向该中心注册发送事件或接收事件。