Bootstrap

Vue2组件通信方式

Vue2组件通信方式包括如下几种方式

  • props、$emit(父传子props,子传父$emit)
  • $emit、$on(即EventBus传值,依赖全局Vue干线)
  • provide、inject(父组件通过provide提供参数,子孙组件通过inject注入参数)
  • $attrs、$listeners(创建高层次组件时使用,attrs包含了父组件中没有被props声明的参数,listeners包含了父组件中不含.native修饰器的事件监听器)
  • Vuex通信

1、父子传参(props和$emit)

父组件

//父组件
<template>
	<div class="main-panel">
        //子组件
		<banner-module :lang="test" @textFun="textFun" />
		<ensure-module :lang="test" />
	</div>
</template>

<script>
//引入子组件
import bannerModule  from './tabs/banner/index.vue'						
import ensureModule from './tabs/ensure/index.vue'						
export default {
    data () {
        return {
            test: 1    
        }
    },
    //声明子组件
    components :{
		bannerModule,
		ensureModule
	},
    methods:{
        textFun(val){
            console.log(val)
        }
    }    
}
</script>

<style>
	
</style>

子组件不可直接改变父组件的值,需要定义新的变量接受父组件的传递值,将新值使用$emit返回给父组件

<template>
	<div class="product-banner">
		<div class="product-notice">
			<p>{{num}}</p>
		</div>
        <van-button @click="addtest">新增</van-button>
	</div>
</template>

<script>
export default {
    //props接受
	props :{
		lang : {
			type : Number,
			default : 1
		}
	},
    data(){
        return{
            num: this.lang
        }
    },
    methods: {
        addtest(){
            //不可以直接改变父组件的值,需要定义新的变量
            this.num ++
            //通知父组件接受新值
            this.$emit("textFun", this.num)
        }
    }
}
</script>
<style scoped>
</style>

2、$emit和$on(全局组件通信)

利用Vue实例作为中央事件总线,来触发和监听事件。实现父子、兄弟、跨级之间的通信

//A组件
<template>
	<div class="main-panel">
        {{test}}
        <div @click="sendBData">发送</div>
	</div>
</template>

<script>
import eventBus from './utils/bus.js'					
export default {
    data () {
        return {
            test: 1    
        }
    },
    methods:{
        sendBData(){
            this.test ++ 
            //发送receiptData方法到全局Vue
            eventBus.$emit("receiptData", this.test)
        }
    }    
}
</script>
//B组件
<template>
	<div class="main-panel">
        {{number}}
	</div>
</template>

<script>
import eventBus from './utils/bus.js'					
export default {
    data () {
        return {
            number: 0  
        }
    },
    created(){
        //监听receiptData方法
        eventBus.$on("receiptData", (val)=>{
            this.number = val
        })
    },
    methods:{
    }    
}
</script>

bus.js 

import Vue from "vue"
var eventBus  =  new Vue()
export default eventBus

3、provide、inject

provide是一个对象,或者是一个返回对象的函数;inject 是一个字符串数组,或者是一个对象

provideinject绑定不是响应的,所以A组件中值改变,B组件中是不会改变的。

//A组件
<template>
	<div class="main-panel">
        {{text}}
        <p @click="changeText">修改</p>
	</div>
</template>

<script>				
export default {
    provide() {
       return: {
           name: "A组件", //无法修改
           app: this,
           test: this.text
       }     
    },
    data () {
        return {
            text: 1,
            name: 'A',    
        }
    },
    methods: {
        changeText(){
            this.text++  //修改后B组件视图不更新
            this.name = 'C' //修改后B组件视图会更新
        }
    }    
}
</script>
//B组件
<template>
	<div class="main-panel">
        <p>组件A的名称:{{app.name}}</p>
        <p>组件A的text:{{text}},组件B的text:{{num}}</p>
	</div>
</template>

<script>
import eventBus from './utils/bus.js'					
export default {
    inject: ['name', 'app', 'text'],
    data () {
        return {
            num: 1    
        }
    }    
}
</script>

4、$attrs、$listeners

A组件向B(子组件)使用props传递了message参数,C组件是B组件的子组件,这时候如果A向C传递参数的话就用到$attrs 监听C返回的变化就用到了listeners

//A组件
<template>
	<div class="main-panel">
      <B :message="message" @getCData="getCData" @getBData="getBData"></B>
	</div>
</template>

<script>
import B from '...B.vue'				
export default {
    data () {
        return {
            message:'hello',
            messageC:'hello C',
        }
    },
    components: {
        B
    },
    methods:{
        getCData(val){
            console.log("这是C的参数",val)
        },
        getBData(val){
            console.log("这是B的参数",val)
        }
    }    
}
</script>

C组件可以直接触发getCData在于B在调用C的时候使用v-on绑定了$listeners属性
通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的

上面这句话的意思是:如果我们在给B传递数据时,多传递一个名字叫做messageB的参数,但是在B组件中没有去接受messageB参数,那么在C组件中也可以访问到messageB,而message是访问不到的

//B组件
<template>
	<div class="main-panel">
      <p>A组件传给B组件的参数: {{message}}</p>
      <button @click="sendBData">和A交互</button>
      <C v-bind="$attrs" v-on="$listeners"></C>
	</div>
</template>

<script>
import C from '...C.vue'				
export default {
    props: {
        messsage: {
            type: String,
            default: ''
        } 
    },
    data () {
        return {
            b: 1
        }
    },
    components: {
        C
    },
    methods:{
        sendBData(){
            this.$emit("getBData", this.b++)
        }
    }    
}
</script>
//C组件
<template>
	<div class="main-panel">
      <p>A组件传给C组件的参数: {{$attrs.messageC}}</p>
      <button @click="sendCData">和A交互</button>
	</div>
</template>

<script>			
export default {
    data () {
        return {
            c: '我是C组件'
        }
    },
    components: {
        C
    },
    methods:{
        sendCData(){
            this.$emit("getCData", this.c)
        }
    }    
}
</script>

5、Vuex

Vuex是专为 Vue.js 应用程序开发的状态管理模式,收集管理应用的所有组件状态。解决了多个视图依赖同一状态和来自不同视图的行为更改同一个状态的问题

Vuex包含5大模块(state,getters,mutations,actions,modules),后边会有介绍Vuex的文章。

Vuex通信类似于EventBus

创建store.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {  //声明state状态树
   message: {
      title: '',
      content: '',
    },
   messageB: ''
  },
  mutations: {    //mutation中提交需要改变的方法
    sendMessage(state, obj) {
      state.message = {
        title: obj.title,
        content: obj.content,
      }
    },
    sendBMessage(state, val){
        state.messageB = val.BMsg
    }
  }
})

在组件A中获取Vuex的数据,同理可在B组件中获取。如果通过A要改变B的数据可通过单独提供给B的方法修改

//A组件
<template>
	<div class="main-panel">
      <p>获取到的title:{{title}},获取到的content:{{content}}
      <div @click="sendB">点击发送</div>
      <B />
	</div>
</template>

<script>
import B from '...B.vue'				
export default {
    data () {
        return {
            bMessage: '我是B组件'
        }
    },
    components: {
        B
    },
    computed:{
        title(){
            return this.$store.state.message.title
        },
        content(){
            return this.$store.state.message.content
        }
    },
    methods: {
        sendB(){
            // 触发sendBMessage,将B组件的数据存放到store里去
            this.$store.commit('sendBMessage', {
              BMsg: this.bMessage
            })
        }
    }   
}
</script>
;