众所周知,在我们现代开发中必不可少要用到Vue或者React, 那么我们一般父子通信一般会用Props, 虽然官方也会说两个同级兄弟组件你可以传到同级父组件然后分发,但是这样的效率实在令人捉急,层级一多你就蛋疼了(react官方出的context也是为了解决此类问题),既然都是单页应用,我们搞个事件监听和传递不就行了
在以前就有
element.addEventListener('click;', function(){})
首先我们需要借助发布订阅实现几个关键api,on / off / emit
他的原理也相当容易理解,我们维护一个事件队列,如果我们用一个key去增加/触发事件函数获得所需要的值,这样就完成了我们跨组件数据传递的需求
Event.js
class EventEmitter {
constructor() {
this.handersArr = {}
}
on(eventType, handle) {
this.handersArr[eventType] = this.handersArr[eventType] || []
this.handersArr[eventType].push(handle)
}
emit(eventType, ...args) {
if (Array.isArray(this.handersArr[eventType])) {
this.handersArr[eventType].forEach((item) => {
item(...args)
})
}
}
off(eventType) {
this.handersArr[eventType] && delete this.handersArr[eventType]
}
}
export default EventEmitter
当然这样我们就完成了超级简单的事件管理器, 但是这里我们想把它用在vue上会需要做这么几个事情,在created接收其他组件的事件(如果有),同比react就是componentDidMount 然后在destoryed阶段(同比react就是componentWillUnmount)把这个事件摧毁,嗯,如果每次这么做就有点不够先进,而且和其他业务代码揉合在一起,不科学
那我们可以在Event.js搞点事情,
bindVue(handlers) {
const _this = this
let handlersWithVue = {}
return {
created() {
for (const [event, _handler] of Object.entries(handlers)) {
const handler = _handler.bind(this) // 把_handler的this绑定到vue调用环境中去
_this.on(event, handler)
handlersWithVue[event] = handler
}
},
beforeDestroy() {
_this.off(handlersWithVue)
}
}
}
这里涉及到一个奇技淫巧,vue的mixins特征,简单暴力来说,它可以把你需要定制的vue的js部分的逻辑全部塞进你的业务.js里面,并起到作用,咦...这上面说的不就成了。
import EventBus from '../util/bus.js'
export default {
mixins: [EventBus.bindVue({
changeText(value) { // 这里就是on方法啦
this.msg = value
}
})],
[emit:] EventBus.emit({changeText: 666})
当然你会问React怎么实现,因为react真的是class,所以你拿到component真的就是标准对象,所以react的处理更方便点,直接把我们那个bindVue换成这个就成,react建议在constructor里面on监听(其实我们项目还有个hooks的实现23333),把我们需要的事件在componentDidMount执行,componentWillUnmount销毁
bindComponent(component, handlers) {
const didMount = component.componentDidMount
const willUnmount = component.componentWillUnmount
component.componentDidMount = () => {
this.on(handlers)
if (didMount) {
return didMount.apply(component)
}
}
component.componentWillUnmount = () => {
this.off(handlers)
if (willUnmount) {
return willUnmount.apply(component)
}
}
}
其实这里正好运用了JavaScript事件驱动和单线程的特点,比较复杂的是,你要注意this的指向,这里确实还是挺乱的,一不小心就不知道操作的是谁的this了。
网友评论