美文网首页
vue组件之间的几种通讯方式

vue组件之间的几种通讯方式

作者: 广告位招租 | 来源:发表于2019-06-17 19:35 被阅读0次

    1. props和$emit

    最简单常用的方式

    目录结构


    目录结构
    // index.vue
    <template>
      <div>
        <h2>父组件中</h2> 
        输入向子组件传值<input type="text" v-model="foo">
        <child-com :foo="foo" @out="getMsg"></child-com>
        <h2>子组件信息</h2>{{childMsg}}
      </div>
    </template>
    
    <script>
      const childCom = () => import('./components/child')
      export default {
        components: {
          childCom
        },
        data() {
          return {
            foo: '',
            childMsg: ''
          }
        },
        methods: {
          getMsg(v) {
            this.childMsg = v
          }
        }
      }
    </script>
    
    // child.vue
    <template>
      <div>
        <h2>子组件中</h2> {{foo}}
        <br/>
        <button @click="sendMsg">点击向父组件传值</button>
      </div>
    </template>
    
    <script>
      export default {
        props: ['foo'],
        methods: {
          sendMsg() {
            this.$emit('out', 'msg')
          }
        }
      }
    </script>
    

    效果图


    props和$emit传值效果图

    2. vuex

    https://vuex.vuejs.org/

    3. 依赖注入

    使用场景

    当组件嵌套过多,而且所有组件都需要使用根组件(包括但不限于)的某一些内容时(数据或方法),使用依赖注入会比普通的传值更加方便

    使用

    // 依赖注入一个getMap方法
    provide: function () {
      return {
        getMap: this.getMap
      }
    }
    

    然后在任何子组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的属性:

    inject: ['getMap']
    

    相比于$parent,选择依赖注入的好处

    使用依赖注入可以让我们免于暴露整个根组件信息,具体有两点

    • 祖先组件不需要知道哪些后代组件使用它提供的属性
    • 后代组件不需要知道被注入的属性来自哪里

    4. 使用$emit/$on,模拟发布订阅模式

    这里需要利用一个空的vue对象当做事件中心,可以实现组件间的通讯

    目录结构


    目录结构
    // event.js创建一个新的vue实例
    import Vue from 'vue'
    const Event = new Vue()
    
    export default Event
    
    // index.vue
    <template>
      <div> 
        父组件 {{msg}}
        <child-com01></child-com01>
        <child-com02></child-com02>
      </div>
    </template>
    
    <script>
      import Event from './components/event'
    
      const childCom01 = () => import('./components/child01')
      const childCom02 = () => import('./components/child02')
      
      export default {
        components: {
          childCom01,
          childCom02
        },
        data() {
          return {
            msg: ''
          }
        },
        mounted() { // 因为不知道什么时候会触发方法,所以一般会选择在created或者是mounted的时候绑定
          Event.$on('getMsg', v => this.msg = v) //箭头函数内部不会产生新的this,这边如果不用=>,this指代Event
        }
      }
    </script>
    
    // child01.vue
    <template>
      <div>
        子组件01 {{msg}}
      </div>
    </template>
    
    <script>
      import Event from './event'
      export default {
        mounted() {
          Event.$on('getMsg', v => this.msg = v)
        },
        data() {
          return {
            msg: ''
          }
        }
      }
    </script>
    
    // child02.vue
    <template>
      <div>
        <h2>子组件02</h2>
        <button @click="sendMsg">to 父组件和兄弟组件</button>
      </div>
    </template>
    
    <script>
      import Event from './event'
      export default {
        methods: {
          sendMsg() {
            Event.$emit('getMsg', 'child02的数据')
          }
        }
      }
    </script>
    
    点击之后效果

    注意: 在使用$on绑定事件之后,需要主动销毁事件
    例如

    beforeDestroy () {
      Event.$off('getMsg')
    }
    

    5. 使用$attrs/$listeners

    在父组件通过v-bind绑定,但是在子组件中未被props声明的属性可以通过$attrs获取到。

    $listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器


    目录结构
    // index.vue
    <template>
      <div> 
        父组件
        <child-com01 :msg1="msg1" :msg2="msg2" :msg3="msg3" :msg4="msg4" @indexfuc="indexfuc" @indexfuc2="indexfuc2" @indexfuc3="indexfuc3"></child-com01>
      </div>
    </template>
    
    <script>
    
      const childCom01 = () => import('./components/child01')
      
      export default {
        components: {
          childCom01
        },
        data() {
          return {
            msg1: 'm1',
            msg2: 'm2',
            msg3: 'm3',
            msg4: 'm4'
          }
        },
        methods: {
          indexfuc() {
            console.log('根组件方法1')
          },
          indexfuc2() {
            console.log('根组件方法2')
          },
          indexfuc3() {
            console.log('根组件方法3')
          }
        }
      }
    </script>
    
    // child01.vue
    <template>
      <div>
        子组件01收到的数据 {{$attrs}}
        props接收的数据{{msg1 + ' ' + msg2}}
        <child-com02 v-bind="$attrs" v-on="$listeners"></child-com02>
      </div>
    </template>
    
    <script>
      const childCom02 = () => import('./child02')
    
      export default {
        components: {
          childCom02
        },
        props: ['msg1', 'msg2'],
        mounted() {
          console.log(this.$attrs, '---child1中')
          console.log(this.$listeners, '---child1中')
          this.$listeners.indexfuc2()
        }
      }
    </script>
    
    // child02.vue
    <template>
      <div>
        子组件02收到的数据 {{$attrs}}
      </div>
    </template>
    <script>
    export default {
      mounted() {
        console.log(this.$listeners, '---child02中')
        this.$listeners.indexfuc3()
      }
    }
    </script>
    
    
    执行结果

    这里的child02是child01的子组件,三个组件是嵌套关系,child02可以拿到全部的属性和方法

    6. $refs和$parent、$children

    使用ref给组件赋值一个ID

    <base-input ref="usernameInput"></base-input>
    

    之后使用this.$refs.usernameInput来访问这个组件

    this.$refs.usernameInput
    

    或者在组件中使用来获取数据

    this.$parent
    this.$children
    

    但是这几种无法实现跨级或兄弟组件之间传递消息,在使用过程中,应该酌情使用以上几种方法

    相关文章

      网友评论

          本文标题:vue组件之间的几种通讯方式

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