vue有多种通信方式。
1.父子组件用props。 2.非父子组件用Event Bus。 3.项目复杂,用Vuex状态管理。
1. props和$emit
父子组件通信的方式,通过props参数和$emit事件建立通信。
props是父组件向子组件传递的参数,$emit是子组件向父组件通信触发的事件。
// 父组件
<div>
<child :Father_value="Father_value" @getValue="getvalue"></child>
</div>
<script>
export default{
data(){
return{
Father_value:'hello,我是父组件定义的data'
}
},
methods:{
getvalue(child_val){
console.log(child_val)//我是子组件传给你的值哦。
}
}
}
</srcipt>
// 子组件
<div @click="post"> {{Father_value}}</div>
<!-- hello,我是父组件定义的data -->
<script>
export default{
props:['Father_value'],
methods:{
post(){
this.$emit('getValue','我是子组件传给你的值哦。')
}
}
}
</srcipt>
- 子组件可以修改父组件的值吗?
可以。使用修饰符.sync。
// 父组件
<div>
<child :Father_value.sync="Father_value"></child>
</div>
<script>
export default{
data(){
return{
Father_value:'hello,我是父组件定义的data'
}
}
}
</srcipt>
// 子组件
<div> {{Father_value}}</div>
<div @click.stop="changefATHERVal"></div>
<!-- hello,我是父组件定义的data -->
<script>
export default{
props:['Father_value'],
methods:{
changefATHERVal(){
this.$emit('update:Father_value','更新它')
}
}
}
</srcipt>
2. 中央事件总线Bus
父子、兄弟、跨级的通信方式。
1.使用一个空的Vue实例作为事件总线
2.通过该空Vue实例来监听和触发事件
3.bus.$emit触发事件,bus.$on监听触发的事件。
// 空vue实例
import Vue from 'vue'
export default new Vue()
<!--引入组件A,B-->
<comA></comA>
<comB></comB>
<script>
export default{
components:{
comA,
comB
}
}
</script>
A组件
<button @click="sendMsg">告诉组件B</button>
<script>
import bus from './bus'
export default{
methods:{
sendMsg(){
bus.$emit('send','你好,b组件')
}
}
}
</script>
B组件
<div>{{msg}}</div>
<script>
import bus from './bus'
export default{
data(){
return{
msg:'start'
}
}
created(){
bus.$on('send',data=>{
this.msg = data
})
}
}
</script>
3. 依赖注入:provied和inject
子孙组件通信,允许一个祖先组件向其所有子孙组件中注入一个依赖,不论层次有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。
可用于vue刷新页面。
父组件:
<div>
<child></child>
</div>
<script>
export default{
data(){
return{
isRouterAlive:true
}
},
provide(){
return{
testData:'我是父组件的值',
reload:this.reload
}
},
methods:{
reload(){
this.isRouterAlive = false
this.$nextTick(()=>{
this.isRouterAlive = true
})
}
}
}
</script>
子组件:
<div>我是子组件,来自父组件的消息:{{testData}}</div>
<!-- hello,我是父组件定义的data -->
<script>
export default{
inject:['reload','testData'],
methods:{
update(){
this.reload()
}
}
}
</srcipt>
4. vuex
所有组件共享状态。
另一篇文中详细介绍:Vuex的使用详解
5. $parent/$children与 ref
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。
$parent / $children:访问父 / 子实例
需要注意的是:这两种都是直接得到组件实例,无法在跨级或兄弟间通信。使用后可以直接调用组件的方法或访问数据。我们先来看个用 ref来访问组件的例子
子组件:
// component-a 子组件
export default {
data () {
return {
title: 'Vue.js'
}
},
methods: {
sayHello () {
window.alert('Hello');
}
}
}
<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(); // 弹窗
}
}
</script>
6. $attrs和 $listeners
跨级通信,子孙组件通信,多级组件嵌套通信。
-
$attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。 -
$listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件
父组件:
<template>
<div>
<h2>浪里行舟</h2>
<child-com1
:foo="foo"
:boo="boo"
:coo="coo"
:doo="doo"
title="前端工匠"
></child-com1>
</div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
components: { childCom1 },
data() {
return {
foo: "Javascript",
boo: "Html",
coo: "CSS",
doo: "Vue"
};
}
};
</script>
子组件:
<template class="border">
<div>
<p>foo: {{ foo }}</p>
<p>childCom1的$attrs: {{ $attrs }}</p>
<child-com2 v-bind="$attrs"></child-com2>
</div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
components: {
childCom2
},
inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
props: {
foo: String // foo作为props属性绑定
},
created() {
console.log(this.$attrs); // { "boo": "Html", "coo": "CSS", "doo": "Vue", "title": "前端工匠" }
}
};
</script>
孙组件:
<template>
<div class="border">
<p>childCom3: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
props: {
coo: String,
title: String
},
created() {
console.log(this.$attrs); // {"doo": "Vue"}
}
};
</script>
$attrs表示没有继承数据的对象,格式为{属性名:属性值}。Vue2.4提供了$attrs , $listeners来传递数据与事件,跨级组件之间的通讯变得更简单。
简单来说:$attrs与$listeners 是两个对象,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。
7. v-model
父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input',val)自动修改v-model绑定的值。
引申提问
怎么访问到子组件的实例或者子元素?
可以通过this.$refs
在组件中怎么访问到根实例?
可以通过this.$root
如何在子组件中访问父组件的实例?
this.$parent拿到父组件实例
this.$children拿到子组件实例(数组)