美文网首页Devlopment
巧用Vue Mixins实现跨级组件通信(Event Bus)

巧用Vue Mixins实现跨级组件通信(Event Bus)

作者: ryderdu | 来源:发表于2019-04-16 18:46 被阅读0次

    众所周知,在我们现代开发中必不可少要用到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了。

    相关文章

      网友评论

        本文标题:巧用Vue Mixins实现跨级组件通信(Event Bus)

        本文链接:https://www.haomeiwen.com/subject/fadiwqtx.html