眾所周知抖甘,在我們現(xiàn)代開發(fā)中必不可少要用到Vue或者React, 那么我們一般父子通信一般會用Props, 雖然官方也會說兩個同級兄弟組件你可以傳到同級父組件然后分發(fā),但是這樣的效率實在令人捉急召噩,層級一多你就蛋疼了(react官方出的context也是為了解決此類問題),既然都是單頁應(yīng)用逸爵,我們搞個事件監(jiān)聽和傳遞不就行了
在以前就有
element.addEventListener('click;', function(){})
首先我們需要借助發(fā)布訂閱實現(xiàn)幾個關(guān)鍵api具滴,on / off / emit
他的原理也相當(dāng)容易理解,我們維護(hù)一個事件隊列师倔,如果我們用一個key去增加/觸發(fā)事件函數(shù)獲得所需要的值构韵,這樣就完成了我們跨組件數(shù)據(jù)傳遞的需求
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
當(dāng)然這樣我們就完成了超級簡單的事件管理器, 但是這里我們想把它用在vue上會需要做這么幾個事情,在created接收其他組件的事件(如果有)趋艘,同比react就是componentDidMount 然后在destoryed階段(同比react就是componentWillUnmount)把這個事件摧毀疲恢,嗯,如果每次這么做就有點不夠先進(jìn)瓷胧,而且和其他業(yè)務(wù)代碼揉合在一起显拳,不科學(xué)
那我們可以在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調(diào)用環(huán)境中去
_this.on(event, handler)
handlersWithVue[event] = handler
}
},
beforeDestroy() {
_this.off(handlersWithVue)
}
}
}
這里涉及到一個奇技淫巧搓萧,vue的mixins特征杂数,簡單暴力來說,它可以把你需要定制的vue的js部分的邏輯全部塞進(jìn)你的業(yè)務(wù).js里面瘸洛,并起到作用揍移,咦...這上面說的不就成了。
import EventBus from '../util/bus.js'
export default {
mixins: [EventBus.bindVue({
changeText(value) { // 這里就是on方法啦
this.msg = value
}
})],
[emit:] EventBus.emit({changeText: 666})
當(dāng)然你會問React怎么實現(xiàn)反肋,因為react真的是class那伐,所以你拿到component真的就是標(biāo)準(zhǔn)對象,所以react的處理更方便點石蔗,直接把我們那個bindVue換成這個就成罕邀,react建議在constructor里面on監(jiān)聽(其實我們項目還有個hooks的實現(xiàn)23333),把我們需要的事件在componentDidMount執(zhí)行养距,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事件驅(qū)動和單線程的特點诉探,比較復(fù)雜的是,你要注意this的指向铃在,這里確實還是挺亂的,一不小心就不知道操作的是誰的this了。