Vue组件通信
props/$emit
- 父组件向子组件传值
在子组件中定义 props 选项,在父组件中通过 v-bind:props属性值
的方式传值给子组件。
<!-- Children.vue -->
<template>
<div>
<ul>
<li v-for="item in list" :key="item.index">{{item.name}}</li>
</ul>
</div>
</template>
<script>
export default {
props: ['list']
}
</script>
<!-- Parent.vue -->
<template>
<Children v-bind:list="list"></Children>
</template>
<script>
import Children from './Children'
export default {
components: {
Children
},
data() {
return {
list: [
{ name: "HTML", index: 1 },
{ name: "CSS", index: 2 },
{ name: "JavaScript", index: 3 }
]
}
}
}
</script>
- 子组件向父组件传值
在子组件上用 emit
来绑定一个自定义事件,emit
方法第二个参数就是要传递给父组件的值。在父组件中通过 v-on:子组件自定义事件名
的方式监听这个自定义事件并接收参数。
<!-- Children.vue -->
<template>
<div>
<button @click="transfer">给父组件传值</button>
</div>
</template>
<script>
export default {
methods: {
transfer() {
this.$emit("send-val", "hello world");
}
}
}
</script>
<!-- Parent.vue -->
<template>
<div>
<Children v-on:send-val="getVal"></Children>
<p>{{text}}</p>
</div>
</template>
<script>
import Children from './Children'
export default {
components: {
Children
},
data() {
return {
text: ''
}
},
methods: {
getVal(param) {
this.text = param;
}
}
}
</script>
$parent/$children
$parent
可以获得当前实例的父实例,$children
可以获得当前实例的直接子组件。$children
得到的是一个数组,但子组件的顺序是不确定的。
<!-- Children.vue -->
<template>
<div>
<p>在子组件中得到父组件的值:{{getParentVal}}</p>
</div>
</template>
<script>
export default {
data() {
return {
childText: "child"
}
},
computed: {
getParentVal() {
return this.$parent.parentText;
}
}
}
</script>
<!-- Parent.vue -->
<template>
<div>
<button @click="getChildrenVal">得到子组件的值</button>
<p>在父组件中得到子组件的值:{{childText}}</p>
<Children></Children>
</div>
</template>
<script>
import Children from './Children'
export default {
components: {
Children
},
data() {
return {
parentText: "parent",
childText: ""
}
},
methods: {
getChildrenVal() {
this.childText = this.$children[0].childText
}
}
}
</script>
provide/inject
在父组件中使用 provide
提供一个对象或一个返回对象的函数,在子组件中使用 inject
注入一个变量。这种方法可以用于多层嵌套的组件之间的通信。
<!-- Children.vue -->
<template>
<div>
<p>在Children中得到的值:{{foo}}</p>
</div>
</template>
<script>
export default {
inject: {
foo: {
// 如果它需要从一个不同名字的 property 注入,则使用 from 来表示其源 property:
from: 'bar',
// 设置默认值
default: 'foo'
}
}
}
</script>
<!-- Parent.vue -->
<template>
<div>
<p>在Parent中得到的值:{{foo}}</p>
<Children></Children>
</div>
</template>
<script>
import Children from './Children'
export default {
components: {
Children
},
inject: ['foo']
}
</script>
<!-- GrandParent.vue -->
<template>
<div>
<Parent></Parent>
</div>
</template>
<script>
import Parent from './Parent.vue'
export default {
components: { Parent },
provide: {
foo: 'hello',
bar: 'world'
}
}
</script>
ref/$refs
在子组件上使用 ref
,引用指向的是组件实例,在父组件上使用 $refs
可以得到这个组件实例,$refs
返回的是一个数组。
<!-- Children.vue -->
<template>
<div></div>
</template>
<script>
export default {
data() {
return {
foo: 'hello'
}
},
methods: {
bar() {
console.log('bar');
}
}
}
</script>
<!-- Parent.vue -->
<template>
<div>
<Children ref="children"></Children>
</div>
</template>
<script>
import Children from './Children'
export default {
components: {
Children
},
mounted() {
const children = this.$refs['children'];
console.log(children.foo);
children.bar();
}
}
</script>
eventBus
创建一个 Vue 实例(作为事件总线)并将其导出,其他组件导入这个事件总线后,可以向这个事件总线注册发送事件和接收事件,所有组件都可以通知其他组件。可以用于兄弟组件通信和父子组件通信。
<!-- EventBus.vue -->
<script>
import Vue from 'vue'
export default new Vue;
</script>
<!-- Children.vue -->
<template>
<div>
<button @click="sendToParent">sendToParent</button>
</div>
</template>
<script>
import EventBus from './EventBus.vue'
export default {
methods: {
sendToParent() {
EventBus.$emit('sayHello', 'hello')
}
}
}
</script>
<!-- Parent.vue -->
<template>
<div>
<Children></Children>
</div>
</template>
<script>
import Children from './Children'
import EventBus from './EventBus.vue';
export default {
components: {
Children
},
mounted() {
EventBus.$on('sayHello', msg => {
console.log(msg);
})
}
}
</script>
移除对事件的监听:
EventBus.$off('sayHello');
$attrs/$listeners
$attrs
包含父组件中所有 attribute 绑定,不包括这三类:作为 prop 传递给子组件的 attribute、class、style,可以通过 v-bind="$attrs"
传入内部组件。$listeners
包含了父作用域中的 (不含 .native
修饰器的) v-on
事件监听器,可以通过 v-on="$listeners"
传入内部组件。这种方式可以用于跨级通信。
<!-- Children.vue -->
<template>
<div>
<p>子组件:</p>
<p>props: {{ prop2 }}</p>
<p>$attrs: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
data() {
return {
text: 'children'
}
},
inheritAttrs: false,
props: ['prop2'],
mounted() {
this.$emit('method2', this.text);
}
}
</script>
<!-- Parent.vue -->
<template>
<div>
<p>父组件:</p>
<p>props: {{ prop1 }}</p>
<p>$attrs: {{ $attrs }}</p>
<!-- 使用v-bind="$attrs"把GrandParent中定义的attrs传入Children -->
<!-- 使用v-on="$listeners"把GrandParent中定义的事件传入Children -->
<Children v-bind="$attrs" v-on="$listeners"></Children>
</div>
</template>
<script>
import Children from './Children'
export default {
components: {
Children
},
data() {
return {
text: 'parent'
}
},
inheritAttrs: false,
props: ['prop1'],
mounted() {
this.$emit('method1', this.text);
}
}
</script>
<!-- GrandParent.vue -->
<template>
<div>
<Parent :prop1="name" :prop2="age" @method1="onMethod1" @method2="onMethod2"></Parent>
</div>
</template>
<script>
import Parent from './Parent.vue'
export default {
components: { Parent },
data() {
return {
name: 'Tom',
age: 12
}
},
methods: {
onMethod1(msg) {
console.log(`${msg} run...`);
},
onMethod2(msg) {
console.log(`${msg} run...`);
},
}
}
</script>
Vuex
参考:https://www.tongjiebin.cn/posts/5c4e.html
总结
父子组件通信:props/$emit、$parent/$children、provide/inject、ref/$refs
兄弟组件通信:eventBus、Vuex
跨级组件通信:provide/inject、$attrs/$listeners、Vuex