Vue 组件间通信

594 阅读1分钟

1.组件间通信的方式

  1. 父子组件
    1. 使用propsemit(),通过事件通信
    2. 通过this.$refs或者$parent和$children取得父子元素方式通信
    3. 子组件通过设置插槽<slot name=''></slot>实现父传子通信
  2. 爷孙组件
    1. 使用两次propsemit(),通过爷爷爸爸通信,爸爸儿子通信实现爷孙通信
    2. $attr$listeners
  3. 任意组件
    1. 使用 eventBus = new Vue() 来通信,eventBus.$oneventBus.$emit 是主要API
    2. 使用 Vuex 通信

2. 父子通信

2.1propsemit()

2.1.1 父传子:父亲给儿子绑定属性,儿子通过props接收
//父组件
<Child :name="father" :f_data="message"/>
//子组件
props:['name','f_data']
//子组件2
props:{ 
  name:{
    type:String,
    default: 'father',
  },
  f_data:{
     type: String|Number,
     validator(){}
  }
}
2.1.2 子传父:子组件通过emit()调用父组件在子组件上v-on绑定的方法,以向方法传参的方式通信
//父组件
<Child v-on:handle='changeMsg'></Child>
//子组件 向父组件传递value数据
<button @click="$emit('handle',value)"></button>

2.2 this.$refs或者$parent和$children,都是获取父亲或儿子的vue实例

//子组件
<template>
    <button>click me </button>
</template>
<script>
    export default {
        data(){
        return{
            sonMessage:'儿子的信息'
       },
        mounted(){
        console.log(this.$parent.$el.innerHTML);
        //<div><button>click me </button></div> <p>爸爸组件</p>
        }
    }
    
</script>
//父组件
<template>
<div>
 <child ref='childRef'>click me </child>
 <p>爸爸组件</p>
</div>
</template>

<script>
    export default {
        data(){
            return{
            fatherMessage:'父亲的信息'
            }
        }
    },
mounted(){
        console.log(this.$refs.childRef.sonMessage); //儿子的信息
        console.log(this.$children[0].sonMessage); //儿子的信息
        }
</script>

2.3 <slot></slot>

父组件

<div>
    <Child>这是默认内容
        <template v-slot:name>
          张三
        </template>
    <Child>
    
</div>

子组件

<div>
    <slot></slot>  <!--这是默认内容-->
    <slot name='title'></slot> <!--张三-->
</div>

3. 爷孙通信

3.1 使用两次propsemit()

爷爷组件

<template>
    <parent name='zhanshan' @onParentClick="sendMessage" ></parent>
</template>

<script>
import Vue from 'vue'
import Parent from './parent.vue'
Vue.component('parent', Parent);
export default {
    methods: {
    sendMessage(sonMsg){
        console.log(sonMsg)   //来自孙子的信息
        }
    }
}
</script>

父亲组件

<template>
    <child :name='name' @onChildClick="$emit('onParentClick',arguments[0])" ></child>
</template>

<script>
import Vue from 'vue'
import Child from './child'
Vue.component('child', Child);
export default {
    props:['name']
}
</script>

孙子组件

<template>
    <button @click="$emit('onChildClick','来自孙子的信息')" >click me </button>
</template>
<script>
export default {
    props: ['name']   //'zhangshan'
}
</script>

爷爷通过向父亲设置name属性,父亲接收再设置,从而儿子接收到爷爷的信息。而儿子通过emit()调用爷爷传给父亲的方法,向爷爷传递参数完成通信

3.2 使用$attr$listeners简化上述3.1步骤

使用$attr的主要代码

// 爷爷
<Parent name="zhangshan"/>

// 父亲
<Child v-bind="$attrs"/>

// 孙子 props接收
<div>{{name}}</div>
props:['name']

// 孙子 props 不接收
<div>{{$attrs.name}}</div>

使用$listeners的主要代码

//爷爷
<parent @onChildClick="sendMessage" ></parent>

methods: {
    sendMessage(sonMsg){
        console.log(sonMsg)   //来自孙子的信息
        }
//父亲
<child v-on="$listeners" ></child>

//孙子
<button @click="$emit('onChildClick','来自孙子的信息')" >click me </button>

4. 任意组件通信

4.1 声明一个全局 Vue 实例变量 EventBus ,把需要通信的数据,上传到这个变量上,能实现各个组件的通信。相当于组件订阅eventBus,某个组件向eventBus传递信息,则eventBus向其他所有订阅它的组件发布该信息

兄弟通信示例

//父组件
data(){
        return{
            eventBus:new Vue()
        }
    },
provide(){  //提供事件中心,使得其所有子孙组件可以使用到eventBus,或者作为js用import引入
    return{
        eventBus:this.eventBus
          }
        },
mounted(){
    this.eventBus.$on('click',(a_message)=>{  //监听eventBus的信息
        console.log(a_message);   //childB的信息
    })

//ChildA组件
<template>
<div>
    <button @click='onClickFun'>childA按钮</button>
</div>
</template>
<script>
export default {
    inject:['eventBus'], //接收事件中心
    data(){
        return{
            a_message:'childB的信息'
            }
        },
     methods: {
        onClickFun(){//点击按钮,向eventBus发送信息 a_message
            this.eventBus.$emit('click',this.a_message)
        }
    }
</script>
//ChildB组件
inject:['eventBus'],  //接收事件中心
mounted(){
    this.eventBus.$on('click',(a_message)=>{  //监听eventBus的信息
        console.log(a_message);   //childB的信息
    })

4.2 Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

访问state数据
//store.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
//自定义共享状态
    state: {
        isMsg: true
    }
});
//main.js
import store from "./store";

new Vue({
  store,   //将store挂载到Vue实例中
  render: h => h(App)
}).$mount("#app");
<!--App.vue-->
<div id='app'>{{$store.state.isMsg}}</div>   <!--true-->
通过mutation修改数据
<!--App.vue-->
<button @click = 'onClick'>修改VueX中的isMsg</button>

methods:{
    onClick(){
      this.$store.commit('onChangeMsg',false) //第一个参数为mutation名字
    }
  },
//store.js
export default new Vuex.Store({
    state: {
        isMsg: true
    },
    mutations: {    //修改数据唯一途径,专注于修改数据好多年
        onChangeMsg(state, data) {
            state.isMsg = data;
            console.log('修改了data');
        }
    },
通过actions 发送异步请求
//app.vue
<button @click='onDispatch'>通过actions发送异步请求</button>
<span>OuterData:{{$store.state.outerData}}</span> //异步请求的数据
 methods:{
    onDispatch(){
      this.$store.dispatch("getOuterData")
    }
//store.js
export default new Vuex.Store({
        state: { 
        outerData: ''       //将异步请求获取的数据存到state中,下次请求直接从state中拿
    },
    mutations: {
        onGetOuterData(state, data) {
            state.outerData = data;
        }

    },
    actions: {
        getOuterData(state) {
            axios({
                url: 'xxxx',  //请求数据的地址
                headers: {}
            }).then((res) => {
                state.commit('onGetOuterData',res.data)
            })
        }
    },
});

vuex.png 总结:根据官方流程图,VueX修改数据的顺序为,通过Dispatch方法使用Actions请求异步数据,通过Commit方法提交到Mutations中,再通过commit方法将数据添加或修改到State中