兄弟组件之间的传值(bus、vuex、根对象)三种方法详解

143 阅读2分钟

有时候两个组件也需要通信(非父子关系),当然Vue2.0提供了Vuex,但在简单的场景下,可以使用一个空的Vue实例作为中央事件总线。

方法一:用eventBus

<div id="app">
    <c1></c1>
    <c2></c2>
</div>
 

var Bus = new Vue(); //为了方便将Bus(空vue)定义在一个组件中,在实际的运用中一般会新建一Bus.js
Vue.component('c1',{ //这里已全局组件为例,同样,单文件组件和局部组件也同样适用
template:'<div>{{msg}}</div>',
  data: () => ({
    msg: 'Hello World!'
  }),
  created() {
    Bus.$on('setMsg', content => { 
      this.msg = content;
    });
  }
});
Vue.component('c2',{
  template: '<button @click="sendEvent">Say Hi</button>',
  methods: {
    sendEvent() {
      Bus.$emit('setMsg', 'Hi Vue!');
    }
  }
});
var app= new Vue({
    el:'#app'
})

在实际运用中,一般将Bus抽离出来:

Bus.js

import Vue from 'vue'
const Bus = new Vue()
export default Bus

组件调用时先引入

组件1

import Bus from './Bus'

export default {
    data() {
        return {
            .........
            }
      },
  methods: {
        ....
        Bus.$emit('log', 120)
    },

  }        

组件2

import Bus from './Bus'

export default {
    data() {
        return {
            .........
            }
      },
  methods: {
        ....
   Bus.$on('log', content => { 
      console.log(content)
    });
 }, 
} 

但这种引入方式,经过webpack打包后可能会出现Bus局部作用域的情况,即引用的是两个不同的Bus,导致不能正常通信

方法二:直接将Bus注入到Vue根对象中

import Vue from 'vue'
const Bus = new Vue()

var app= new Vue({
    el:'#app',
   data:{
    Bus
    }  

})

在子组件中通过this.root.Bus.root.Bus.on(),this.root.Bus.root.Bus.emit()来调用

方法三:用Vuex

假如现在有一个需求:在首页(index.vue)调用了组件A(componentA.vue),和组件B(componentB.vue),想通过主键B的点击事件,触发组件A的事件

步骤:

1.先安装vuex,执行 npm install vuex --save代码,安装vuex

2.在main.js文件中导入vuex,代码如下:

import Vue from 'vue'
import App from './App'
import router from './router'
import vuex from 'vuex'
Vue.config.productionTip = false
Vue.use(vuex)
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

3.在根目录下创建文件夹:vuex,然后添加store.js文件,store.js文件代码如下:

import vue from 'vue'
import Vuex from 'vuex'
vue.use(Vuex)
const state={
    count:1
}

const mutations={
    add(state){
        state.count++;
    }
}

export default new Vuex.Store({
    state,mutations
})

4.在index.vue中引用A组件和B组件,代码如下:

<template>
  <div>
      <h1>组件A调用</h1>
      <compontentA></compontentA>
      <h1>组件B调用</h1>
      <compontentB></compontentB>
  </div>
</template>

<script>
import compontentA from './componentA'
import compontentB from './componentB'
export default {
  data() {
    return {
      msg: "Welcome to Your Vue.js App"
    };
  },
  components:{
    compontentA,
    compontentB
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1,
h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

5.组件A代码:

<template>
    <div>
        <h1>我是组件A</h1>
        {{$store.state.count}}
    </div>
</template>
<script>
import store from '@/vuex/store'
export default {
    data(){
        return{
            result:0
        }
    },
    created(){
     
    },
    store,
    methods:{
      watchstore(){
          alert("从B组件触发A组件");
      }
    },
    watch:{
      '$store.state.count':function(val){
         this.watchstore();
      }
    }
}
</script>
<style scoped>

</style>

注意,监听状态的方式和监听其他变量和方法的方式有点不一样,代码:

 '$store.state.count':function(val){
         this.watchstore();
      }

6.组件B代码如下:

<template>
    <div>
        <h1>我是组件b,利用组件b的事件,控制状态,达到修改组件A的目的</h1>
        <button @click="$store.commit('add')">操作状态+1</button>
      
    </div>
</template>
<script>
import store from '@/vuex/store'
export default {
    store,
    methods:{

    }
}
</script>
<style scoped>

</style>

以上步骤就可以达到使用组件B的点击事件控制组件A的内部方法的效果,vuex的细节应用,我们下次具体讨论,本次关键点在于A组件的监听。