Vue 非父子组件传值

638 阅读2分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

在Vue的组件通信过程中,除了之前讲到的 父子组件通信,本文讲解一下 Vue 项目中的 非父子组件之间的传值方式

事件总线 bus

vue官网指出,可以使用一个空vue实例作为事件中央线,非父子组件之间的通信,必须要有公共的实例,才能使用 $emit 和 $on 传递数据参数,实现组件之间的通信 

公共实例文件bus.js,作为公共数控中央总线

import Vue from "vue";
export default new Vue();

一个组件A

import Bus from '../bus.js';
export default {
  name: 'aaa',
  data () {
    return {
      value: 'aaa.vue组件!'
    }
  },
  methods:{
    update(){// 定义update方法,并将msg通过txt传给另一个组件
      Bus.$emit('txt',this.value);
    }
  }
}

一个组件B

import Bus from '../bus.js';
export default {
  name: 'bbb',
  data () {
    return {
        value:''
    }
  },
  mounted:function(){
    Bus.$on('txt',function(val){//监听aaa组件的txt事件
      this.value = val
    });
  }
}

这样就可以在两个没有父子关系的组件中,通过第三者bus.js来获取到第一个组件的value

兄弟组件之间与父子组件之间的数据交互,两者相比较,兄弟组件之间的通信其实和子组件向父组件传值有些类似,其实他们的通信原理都是相同的

例如子向父传值也是emitemit和on的形式,只是没有eventBus,其实是父组件来充当了bus这个事件总线的角色 

$attrs/listeners

$attrs 和 listeners 的方式用于多级组件间传值的问题

在对一些组件进行二次封装时可以方便传值,组件A传递到组件C,使用组件B作为桥梁A-B-C

一个组件A (app.vue

<template>
    <div id="app">
        <child1
            :p-child1="child1"
            :p-child2="child2"
            v-on:test1="onTest1"
            v-on:test2="onTest2"> 
        </child1>
        // 监听了两个事件,可以在B组件或者C组件中直接触发
    </div>
</template>
<script>
import Child1 from './Child1.vue';
export default {
    data () {
    return {};
    },
    components: { Child1 },
    methods: {
        onTest1 () {
        console.log('test1 running...');
        },
        onTest2 () {
        console.log('test2 running');
        }
    }
};
</script>

一个组件B (child1

<template>
    <div class="child-1">
        <p>in child1:</p>
        <p>props: {{pChild1}}</p>
        <p>$attrs: {{$attrs}}</p>
        <hr>
        <child2 v-bind="$attrs" v-on="$listeners"></child2>
        // C组件中能直接触发test的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性
        // 通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的)
    </div>
</template>
<script>
import Child2 from './Child2.vue';
export default {
    props: ['pChild1'],
    data () {
    return {};
    },
    inheritAttrs: false,
    components: { Child2 },
    mounted () {
        this.$emit('test1');
    }
};
</script>

一个组件C    

<template>
    <div class="child-2">
        <p>in child2:</p>
        <p>props: {{pChild2}}</p>
        <p>$attrs: {{$attrs}}</p>
        <hr>
    </div>
</template>
<script>
export default {
    props: ['pChild2'],
    data () {
    return {};
    },
    inheritAttrs: false,
    // 如果不想在dom上出现属性,可设置interitAttrs: false
    mounted () {
        this.$emit('test2');
    }
};
</script>

如果组件C中有props属性接受的对象的化,组件A传递的对象就会被自动过滤掉

Vuex

对于更复杂的情况,Vue也有提供更复杂的状态管理模式Vuex来进行处理

附:《Vuex使用方法》