美文网首页vue学习
vue 2.x 仿dispatch和 brocast

vue 2.x 仿dispatch和 brocast

作者: 安石0 | 来源:发表于2019-01-05 09:19 被阅读8次

    vue 在2.0已经去除了dispatch 和brocast,但是又想用它的特性怎么办?

    1 初级版,只能传一个参数

    问题:为什么不用eventBus?如果想要用类似的功能独立于业务项目,不可能在一个项目用一次,就要改一下代码,用eventBus.
    实现原理:假设s.vue要向app.vue发消息,通过options.name的方式找到目标组件target,然后target.$emit(target, eventName, params)自己触发事件.
    核心实现(如下:),可以通过mixins的方式混入。
    dispatch('$option.name','事件名', 参数)

    // emmiter.js
    function broadcast (componentName, eventName, data) {
      this.$children.forEach(child => {
        if (child.$options.name === componentName) {
          child.$emit.call(child, eventName, data)
        } else {
          broadcast.call(child, componentName, eventName, data)
        }
      })
    }
    export default {
      methods: {
        dispatch (componentName, eventName, data) {
          let parent = this.$parent || this.$root
          let name = parent.$options.name
          while (parent && (!name || parent.$options.name !== componentName)) {
            parent = parent.$parent
            if (parent) {
              name = parent.$options.name
            }
          }
          console.log(parent)
          parent.$emit.apply(parent, [eventName].concat(data))
        },
        broadcast (componentName, eventName, data) {
          broadcast.call(this ,componentName, eventName, data)
        }
      }
    }
    

    具体例子:

    // app.vue
    <template>
      <div id="app">
        <input type="text" v-model="rMsg"><button @click="huixin">回信</button>
        <div>hello</div>
        <grand></grand>
      </div>
    </template>
    <script>
    import grand from './components/g'
    import emitter from './components/emmit'
    export default {
      mixins: [emitter],
      name: 'app',
      data () {
        return {
          show: false,
          rMsg: 'sb我收到信息了,考上大学你也找不到工作,还得你爹给你买房!'
        }
      },
      methods: {
        fn (e){
          console.log('消息收到了', e)
        },
        huixin () {
          this.broadcast('son', 'huixin', this.rMsg)
        }
      },
      mounted () {
        this.$on('joy', this.fn)
      },
      components: {
        grand
      }
    }
    </script>
    
    // g.vue
    <template>
      <div>
        我是grand,中文就是爷爷的意识,现在组件建好了,要干大事咯
        <father></father>
      </div>
    </template>
    <script>
    import father from './f'
    export default {
      name: 'grand',
      components: {
        father
      }
    }
    </script>
    
    // f.vue
    <template>
      <div>
        我是father,并且我有一个son
        <son></son>
      </div>
    </template>
    <script>
    import son from './s'
    export default {
      name: 'father',
      components: { son }
    }
    </script>
    
    // s.vue
    <template>
      <div>
        我是son
        <el-form label-width="100px">
          <el-form-item label="喜事">
            <el-input v-model="joyText" style="width: 240px;"></el-input>
          </el-form-item>
        </el-form>
        <el-button @click="transferJoy">向app报喜</el-button>
      </div>
    </template>
    <script>
    import emitter from './emmit'
    export default {
      mixins: [emitter],
      name: 'son',
      data () {
        return {
          joyText: '考上清华大学长河分校'
        }
      },
      created () {
        this.$on('huixin', (data) => {
          console.log('回信', data)
        })
      },
      methods: {
        transferJoy () {
          this.dispatch('app', 'joy', this.joyText)
        }
      }
    }
    </script>
    

    最终效果:


    运行效果

    2 源码实现:

    // 所有的父组件都自己触发事件,自己监听
     Vue.prototype.$dispatch = function (event) {
        var shouldPropagate = this.$emit.apply(this, arguments)
        if (!shouldPropagate) return
        var parent = this.$parent
        var args = toArray(arguments)
        // use object event to indicate non-source emit
        // on parents
        args[0] = { name: event, source: this }
        while (parent) {
          shouldPropagate = parent.$emit.apply(parent, args)
          parent = shouldPropagate
            ? parent.$parent
            : null
        }
        return this
      }
    // 所有的子组件自己触发事件
      Vue.prototype.$broadcast = function (event) {
        var isSource = typeof event === 'string'
        event = isSource
          ? event
          : event.name
        // if no child has registered for this event,
        // then there's no need to broadcast.
        if (!this._eventsCount[event]) return
        var children = this.$children
        var args = toArray(arguments)
        if (isSource) {
          // use object event to indicate non-source emit
          // on children
          args[0] = { name: event, source: this }
        }
        for (var i = 0, l = children.length; i < l; i++) {
          var child = children[i]
          var shouldPropagate = child.$emit.apply(child, args)
          if (shouldPropagate) {
            child.$broadcast.apply(child, args)
          }
        }
        return this
      }
    
    

    相关文章

      网友评论

        本文标题:vue 2.x 仿dispatch和 brocast

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