最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue 组件之间通讯的各种情况

    正文概述 掘金(SoulReader)   2021-02-13   416

    我们都知道 Vue 的两大核心是组件化数据驱动,在 Vue 中,组件之间的值传递是一种十分常见的事情,那么你到底知道多少种组件的值传递的方法呢,接下来由我来带领大家了解一下

    Vue 组件之间的关系

    Vue 的组件根据其在页面上的位置,我认为大致可以分为以下几种:

    父子组件

    什么是父子组件呢? 假如现在页面中有一个根组件ParentComponent,现在我们需要在这个根组件中加入其他内容,例如一张图片,一段具有事件和样式的文字等,我们可以假设这个加入内容的组件名称为ChildrenComponent, 这个新加入的组件ChildrenComponent 相对与 ParentComponent就是子组件, ParentComponent 就是 ChildrenComponent 的父组件,如下所示

      <parent-component>
        <children-component></children-component>
      </parent-component>
    
    兄弟组件

    什么是兄弟组件呢?以上面的父子组件为例,假如现在加入的不是一个组件,而是加入多个组件,加入的这些组件之间的关系就是兄弟组件的关系

      <parent-component>
        <children-component></children-component>
        <children-component></children-component>
        <children-component></children-component>
      </parent-component>
    
    非父子,兄弟关系的组件

    这种组件的关系是怎么形成的呢,可能就是位于不同父组件下的子组件之间的关系

      <parent-component>
        <children-component></children-component>
      </parent-component>
      <other-component></other-component>
    

    比如这种,children-componentother-component 之间的关系都是即非父子,兄弟关系组件

    当然以上说法都不是特别组件,因为 Vue 是一个单页面组件,都位于同一个根组件下面,所以 Vue 中的组件之间都或多或少都是有一些关系

    Vue 组件之间的通讯

    上面介绍完了组件,我们现在介绍一下不同组件之间应该如何通讯

    父子组件
    1. Vue 组件上有个特殊的属性 Props 可以取到通过 v-bind指令或者直接通过 属性 传值 传递过来参数,通常用于父子组件传值
      <parent-component>
        <children-component :type="type" name="name"></children-component>
      </parent-component>
    

    此时子组件可以通过 props 来获取父组件传递过来的参数

      // children-component
      export default {
        // 第一种 (不推介,因为没有类型检测,不利于开发)
        props: ['type', 'name'],
        // 第二种 (推介,可以检查通过 props 传递过来值的类型,利于排错和开发)
        props: {
          type: {
            type: Array,  // 如果需要兼容多重类型检查可以使用数组 [Array, Object, String]
            default: () => {
              return []
            }
          },
          name: {
            type: String,
            default: ''
          }
        }
      }
    
    1. 子组件向父组件传值可以采用 $emit() 来发送事件,父组件采用 v-on 来监听事件发生
      // 子组件
      export default {
        mounted() {
          this.$emit('change')
        }
      }
    
      <parent-component>
        <!-- v-on: 也可以简化成 @ -->
        <children-component v-on:change="handleChange"></children-component>
      </parent-component>
    

    当然我们也可以采用 v-model 来传递参数,但是此时子组件必须要用 props 接收 一个名叫 value 的值,当事件触发时,把新的值通过自定义的 input 事件抛出

    因为 v-model 等价 v-bind:valuev-on:input

    1. $parent$children 也可以实现父子组件之间传值
    1. 父子组件之间也可以通过 $refs 方法来进行通讯

    在子组件上添加属性 ref 值为 refValue, 父组件可以通过 this.$refs[refValue] 或者 this.$refs.refValue 来访问和调用子组件上面的方法和值

    注意: 使用 $ref 获取子组件必须是子组件已经在页面中加载成功了,即在 除beforeCreate, created, destoryed 生命周期函数以外的其他声明周期调用,如果组件是手动控制显示和隐藏,即使用 v-if,此时可以采用 this.$nextTick(() => {this.$refs[refValue]}) 方法来访问子组件的方法

    兄弟组件之间的传值
    1. 通过共有的父组件来进行传值

    子组件通过 $emit 方法调用父组件的方法,然后通过父组件来调用其他的子组件来实现兄弟组件之间之间传值

    1. 通过 $parent 方法

    同父子组件传值,可以使用,但是不推介

    非父子,兄弟关系的组件
    1. Vuex Vue 状态管理工具

    可以使用 Vue 的状态管理工具来进行传值

      // store.js
      /**
        * state: 存储状态管理对象及数据
        * mutations: 同步修改 state 的属性的值,同时只有 mutations 能够修改 state 的值 使用时通过 commit 来调用
        * actions: 异步修改 state 的属性的值,通过调用 mutations 的方法来修改 通过 dispatch 方法调用
        */ 
      export default {
        state: {
          type:1
        },
        mutations: {
          setType(state, type) {
            state.type = type
          },
        },
        actions: {
          setType({commit}, type) {
            commit('setType', type)
          }        
        }
      }
      // a 组件
      export default {
        mounted() {
          this.$store.dispatch('setType', 1)
        }
      }
      // b 组件
      export default {
        mounted() {
          this.$store.state.type
        }
      }
    

    关于 Vuex 的更多使用方法请百度查找官方使用文档

    1. Vue bus 也叫中央事件总线

    定义一个全局的 Vue,通过挂载到 window 对象或者 Vue 实例上面,此时可以通过 Vue bus 的 $emit$on 方法来进行事件传递

      // 第一种
      var bus = new Vue()
      // 发送事件
      bus.$emit('patch')
      // 接收事件
      bus.$on('patch)
      // 第二种 
      Vue.$bus = new Vue()
      // 发送事件
      Vue.$bus.$emit('patch')
      // 接收事件
      Vue.$bus.$on('patch)
    

    进阶方法

    以上都是一些比较简单的组件之间传值的方法,相信在座的各位基本上都用到过,接下来介绍一些比较高端的方法,这些方法我们可能没有用过,也可能没有听说过,接下来让我来带领大家去了解他们,使用他们

    attrsattrs 和 attrs和listeners

    此方法适用于多层父子组件结构进行通讯,因为层级过多,此时使用 $emit$on 方法来进行传值,你需要在需要通讯的两个祖孙组件之间的每个组件都要写上重复的 $emit$on, 增加事件追踪难度,同时难以阅读

    此时可以采用 $attrs$listeners来进行传值

    这种方法所采用的办法就是将祖父组件的 传给 父组件的 属性和监听事件传递给孙组件

    默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上

    <!-- 函数我就不写了,只是做一个简略的展示 -->
      <!-- grandfather 组件 -->
      <grand-father>
        <a-parent :a="a = 4444" :b="b = 5555" @getData="handleGetData" @passData="handlePassdata"></a-parent>
      </grand-father>
    
      <!-- parent 组件 -->
      <a-parent>
        <b-children v-bind="$attrs" v-on="$listeners"></b-children>
      </a-parent>
      <script>
        ...
        // 默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上
        props:[] // 注意如果在此处使用了props接收了参数, 则通过 v-bind 传递给子组件的 $attrs 中就会缺失对应参数
        mounted() {
          console.log(this.$attrs)  // {a: 4444, b: 55555}
          // 如果此时props 接收了 参数 a 那么 console 的值为 { b: 55555 }
          console.log(this.$listeners) // { getData: f(), passData: f()}
        }
        ...
      </script>
    
      <!-- children 组件 -->
      <input v-model="$attrs.a" @input="passData($attrs.a)"  />
      <script>
        ...
        
        mounted() {
          console.log(this.$attrs)  // {a: 4444, b: 55555}
          // 如果此时 props 接收了 参数 a 那么 console 的值为 { b: 55555 }
          // a 的值 也可以通过 $emit 方法传递给祖组件
          console.log(this.$listeners) // { getData: f(), passData: f()}
        }
        methods: {
          passData(val) {
            // 此处发送的事件名称需要与祖组件监听方法一致 即 @passData
            this.$emit('passData', val)
          }
        }
        ...
      </script>
    
    provide 和 inject

    父组件通过 provide 提供变量,子组件通过 inject 注入变量,不管子组件多深,只要调用了 inject 就可以注入 provide 中的数据,而不是局限于只能从当前父组件的 prop 属性来获取数据,只要在父组件的生命周期内,子组件都可以调用

      <!-- grandfather 组件 -->
      <grand-father>
        <a-parent></a-parent>
      </grand-father>
      <script>
        ...
        provide: {
          test: 'test'
        }
        ...
      </script>
    
      <!-- parent 组件 -->
      <a-parent>
        <b-children></b-children>
      </a-parent>
    
      <!-- children 组件 -->
      <input v-model="$attrs.a" @input="passData($attrs.a)"  />
      <script>
        ...
        inject:['test']
        ...
      </script>
    
    boradcast 和 dispatch

    这种方法我不太了解,贴上代码,大家自己体会 (^-^)

    vue1.0中提供了这种方式,但vue2.0中没有,但很多开源软件都自己封装了这种方式,比如min ui、element ui和iview等。

    比如如下代码,一般都作为一个mixins去使用, broadcast是向特定的父组件,触发事件,dispatch是向特定的子组件触发事件,本质上这种方式还是on和emit的封装,但在一些基础组件中却很实用。

      function broadcast(componentName, eventName, params) {
        this.$children.forEach(child => {
          var name = child.$options.componentName;
    
          if (name === componentName) {
            child.$emit.apply(child, [eventName].concat(params));
          } else {
            broadcast.apply(child, [componentName, eventName].concat(params));
          }
        });
      }
      export default {
        methods: {
          dispatch(componentName, eventName, params) {
            var parent = this.$parent;
            var name = parent.$options.componentName;
            while (parent && (!name || name !== componentName)) {
              parent = parent.$parent;
    
              if (parent) {
                name = parent.$options.componentName;
              }
            }
            if (parent) {
              parent.$emit.apply(parent, [eventName].concat(params));
            }
          },
          broadcast(componentName, eventName, params) {
            broadcast.call(this, componentName, eventName, params);
          }
        }
      };
    
    

    起源地下载网 » Vue 组件之间通讯的各种情况

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元