vue组件之间通信有以下三种情况
1、父子组件通信
props/$emit $refs/$parent/$children provide/inject $attrs/$listeners
2、同级组件之间通信
事件总线vm.$emit/vm.$on vuex
3、跨组件通信
vuex、 $attrs/$listeners
组件间通信共有六种方式
一、props/$emit
父组件通过props向下传递给子组件,子组件$emit事件名,父组件v-on事件来接收。
举个栗子:
// 父组件
<template>
<div class="hello">
{{msg}}
<Child v-bind:msg='message' v-on:msgChange='msgChange($event)'></Child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
data() {
return {
message: 'Welcome to Child!'
}
},
components:{
Child
}
}
</script>
// 子组件
<template>
<div>
<h2 @click="msgChange">{{msg}}</h2>
</div>
</template>
<script>
export default {
name:'Child',
props:{ //接收父组件传递过来的值
msg:{
type:String,
default:''
}
},
methods: {
msgChange(){
this.$emit('msgChange',true) //子组件向父组件传值
}
},
}
</script>
总结:父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed。子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。
二、$emit/$on 事件总线
这方法需要通过一个Vue实例来作为中央事件总线,用它来触发事件和监听事件,可以实现任何组件间的通信。(小项目,少量事件总线通信可以使用,项目大的话推荐使用Vuex状态管理)。实现方式:
const vm = new Vue()
vm.$emit(事件名,数据)
vm.$on(事件名,data => {})
三、$attrs/$listeners
$attrs包含了父作用域中不被props所识别的特性绑定,当一个组件没有声明任何props时,所有的值可以通过v-bind='$attrs'传入内部组件中。通常配合 inheritAttrs 选项一起使用。(默认情况下父作用域的不被认作 props 的特性绑定 (attribute bindings) 将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。)
$attrs包含了父作用域中v-on实践监听器(不含.native修饰器的事件)。可以通过v-on='$listeners'传入内部组件。$listeners里存放的是父组件中绑定的非原生事件。
让我们举个栗子:
组件关系A => B => c
A是低层组件
// A组件
<template>
<div>
<h2>A组件</h2>
<component-a
:data1='data1'
:data2='data2'
:data3='data3'
v-on:testChange='testChange'
></component-a>
</div>
</template>
<script>
const componentA = () => import("./componentA.vue");
export default {
components: { componentA },
data() {
return {
data1: "data1",
data2: "data2",
data3: "data3",
};
},
methods:{
testChange(){}
}
};
</script>
// B组件
<template>
<div>
<h2>B组件</h2>
<component-c
v-bind='$attrs'
v-on='$listeners'
v-on:eventChange='eventChange'
></component-c>
</div>
</template>
<script>
import componentC from './componentC.vue'
export default {
components:{componentC},
props:['data1']
data(){
return{
}
},
mounted(){
除了props的所有参数都在$attrs上
console.log(this.$attrs) //{data2: "data2", data3: "data3"}
console.log(this.$listeners) //{testChange: ƒ}
},
methods:{
eventChange(){}
}
}
</script>
// C组件
<template>
<div>
<h2>C组件</h2>
<p>C组件得到的$attrs: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
props: {
data2: String
},
mounted(){
除了props的所有参数都在$attrs上
console.log(this.$attrs) //{ data3: "data3"}
A、B组件的事件会累计
console.log(this.$listeners) //{testChange: ƒ, eventChange: ƒ}
},
};
</script>
四、$parent/$children和$ref
ref:如果在普通的DOM元素上使用,指向的就是DOM元素,如果用在子组件上,就指向组件实例
$parent/$children: 访问父/子实例
以上两种方式都可以直接得到组件实例,可以直接调用组件的方法或者访问数据。举个栗子:
// 父组件
<template>
<component-a ref="comA"></component-a>
</template>
<script>
export default {
mounted () {
const comA = this.$refs.comA;
console.log(comA.title); // Vue.js
comA.sayHello(); // 弹窗
}
}
子组件
export default {
data () {
return {
title: 'Vue.js'
}
},
methods: {
sayHello () {
window.alert('Hello');
}
}
}
</script>
注意:以上两种方式无法在跨级组件或者兄弟组件之间通信,只能用于父子组件间通信。
五、privide 和 inject
简介:Vue2.2.0新增,允许一个祖先组件向其所有子孙后台注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终有效。也就是祖先组件通过provide来提供变量,然后在子孙组件中通过inject来注入变量。
provide/inject主要解决了跨级组件间的通信问题,使用场景:主要是子组件获取上级组件的状态,跨级组件间建立一种主动提供与依赖注入的关系。
举个栗子:
// 父组件
export default{
provide:{
name:'Arya'
}
}
// 子组件
export default{
inject: ['name'],
mounted(){
console.log(this.name) // Arya
}
}
注意:provide和inject绑定并不是响应式的,然而如果你传入一个可监听的对象,其对象的属性还是可响应式的。 也就是以上name如果改变了,后代组件是不会监听到的。 但是如果我们传入的是一个name:{value:'Arya'},这个value的改变是可以监听到的。 此外我们可以传入function,例如我们常需要在子组件编辑了数据,父组件去刷新列表。
// 父组件
export default{
provide(){
return{
refresh: this.refresh
}
},
methods:{
refresh(){
获取新数据
}
}
}
// 子组件
export default{
inject: ['refresh'],
methods:{
handler(){
this.refresh()
}
}
}
怎么实现provide与inject的数据响应式(高阶组件功能,我们后面再学)
六、vuex