zoukankan      html  css  js  c++  java
  • vue兄弟组件之间传值

      前面说了   

        父组件  >>>>  子组件

        子组件   >>>>  父组件

        父组件  <<<<  子组件

        子组件   <<<<  父组件

    相互传值的方式,那两个组件不是父子关系咋办啊?之前面试被问到,问的我一脸懵逼,我当时回答说,localstorage、定义全局变量;

      其实这两种方式也不是不可以,但老二存了数据进去,老大怎么获取呢?老大不知道你啥时候存进去了呀!?

      面试结束我就想,移动端开发有广播,注册广播,发送广播的机制,记得浏览器也有这种机制,那是不是vue里边也有相应的机制呢?

    我一搜,哎呦 ~~我去~~ 真有,(妹的,之前也接触过的,就是通过bus传递,没实际在项目里边用过,所以忘了)。

      那这个bus具体咋整涅:

    1.定义一个单独的js文件,起名为:vueBus.js,然后里边写:

    import Vue from 'vue';
    let bus = new Vue();
    export default bus;

    2.在需要接收信息的地方注册监听事件:先引入bus

      mounted(){
          let self = this
          bus.$on('fromSecond',(data)=>{
              self.res = data//获取到传过来的值
          });
      },

    3.然后发送广播事件:先引入bus

        sendMsg(){
          bus.$emit("fromSecond",this.res)
        }

    注意:先引入bus:

    import bus from '@/api/vueBus.js'
     
    并且发一次,多个注册过的地方都能接收到
    --------------------------------------------------------------------------------------------------------------------------分割线
    那实现原理是什么样的呢?当然知道了上边的内容完全够用了,但在这个人人装b的时代,你不了解原理怎么能够呢,原理你要知道并且深深的知道!
     
    想知道原理就得看源码:
     
    export function eventsMixin (Vue: Class<Component>) {
      const hookRE = /^hook:/
      // 这里是注册事件
      Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
        const vm: Component = this
        if (Array.isArray(event)) {// 这里看到注册事件时候可以传个数组进来
          for (let i = 0, l = event.length; i < l; i++) {//循环着添加事件
            vm.$on(event[i], fn)//调用自己
          }
        } else {// _events是装所有事件的对象
          // 添加进_events去 如果对应的这个事件名已经有方法了就再往里边push一个
          // 如果没有就建一个数组往里边push
          // 所以 你往数组里边放几次执行时候就会执行几次,
          // 同一个事件名 注册几个不同/相同回调方法 都会执行
          (vm._events[event] || (vm._events[event] = [])).push(fn)
          // optimize hook:event cost by using a boolean flag marked at registration
          // instead of a hash lookup
          if (hookRE.test(event)) {
            vm._hasHookEvent = true
          }
        }
        return vm
      }
    
      // 这里是一次性绑定
      Vue.prototype.$once = function (event: string, fn: Function): Component {
        const vm: Component = this
        // 封装一个fn 执行时候移除绑定 这样就实现只能触发一次了
        function on () {
          vm.$off(event, on)
          fn.apply(vm, arguments)
        }
        on.fn = fn
        vm.$on(event, on)// 绑定封装过一次的fn
        return vm
      }
    
      // 移除绑定事件
      Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function): Component {
        const vm: Component = this
        // all
        if (!arguments.length) {
          vm._events = Object.create(null)
          return vm
        }
        // array of events
        // 是数组的话 循环着去解绑
        if (Array.isArray(event)) {
          for (let i = 0, l = event.length; i < l; i++) {
            vm.$off(event[i], fn)
          }
          return vm
        }
        // specific event
        const cbs = vm._events[event]
        if (!cbs) {// 找不到这个事件 你解绑个p呀
          return vm
        }
        if (!fn) {// 解绑时候没有传过来 回调方法 你解绑个p呀
          vm._events[event] = null
          return vm
        }
        // specific handler
        let cb
        let i = cbs.length
        while (i--) {
          cb = cbs[i]
          if (cb === fn || cb.fn === fn) {
            cbs.splice(i, 1)//找到他 并且移除他
            break
          }
        }
        return vm
      }
    
      // 发送事件
      Vue.prototype.$emit = function (event: string): Component {
        const vm: Component = this
        if (process.env.NODE_ENV !== 'production') {
          const lowerCaseEvent = event.toLowerCase()
          if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
            tip(
              `Event "${lowerCaseEvent}" is emitted in component ` +
              `${formatComponentName(vm)} but the handler is registered for "${event}". ` +
              `Note that HTML attributes are case-insensitive and you cannot use ` +
              `v-on to listen to camelCase events when using in-DOM templates. ` +
              `You should probably use "${hyphenate(event)}" instead of "${event}".`
            )
          }
        }
        // 找到这个方法
        let cbs = vm._events[event]
        if (cbs) {
          cbs = cbs.length > 1 ? toArray(cbs) : cbs

        // 把传过来的参数去掉第一个,转化成参数数组
          const args = toArray(arguments, 1)
          const info = `event handler for "${event}"`
          for (let i = 0, l = cbs.length; i < l; i++) {
            // 执行这些方法
            invokeWithErrorHandling(cbs[i], vm, args, vm, info)
          }
        }
        return vm
      }
    }

    可以看到:添加事件时候会把方法放到Vue的_events对象上,这个对象的key是事件名,value是fn数组;你调用$emit时候,他会根据你传过来的事件名称去找到对应的fn数组,循环执行之。

    看源码意外收获:

      1. 注册事件时候事件名而已传数组

      2. 一个/组事件名可以绑定不同的方法,执行时候按顺序一并执行

      3. 解除事件监听时候需要传事件名和方法进来

      4. 注册一次性事件是怎么完成的

     
    over!
  • 相关阅读:
    Cannot set property 'branchdata' of undefined
    关闭Vue Eslint语法检查
    Webpack前世今生
    SpringCloud 之 Netflix Hystrix 服务监控
    Spring Cloud 之 Netflix Hystrix 服务容错
    Java设计模式之建造者模式(Builder Pattern)
    Java设计模式之工厂模式(Factory Pattern)
    数据库表的字段有默认值,如何修改或者去掉这个默认值
    前端基础进阶(十五):详解 ES6 Modules
    JS基础知识题(中)作用域、闭包
  • 原文地址:https://www.cnblogs.com/rainbowLover/p/12068885.html
Copyright © 2011-2022 走看看