provide 和 inject
官方释义这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
- 使用
在祖先组件使用provide向下注入依赖,在所有的子孙组件可以使用inject接收到传输的数据。 - 示例
祖先组件
<template>
<div class="grandfather">
祖先组件
<father></father>
</div>
</template>
<script>
import father from "./father";
export default {
provide: {
grandFtext: "一段来自祖先组件的数据"
}
};
</script>
注入
父组件
<template>
<div class="father">
父组件
<p>{{ text }}</p>
<son></son>
</div>
</template>
<script>
export default {
inject: ["grandFtext"],
data() {
return {
text: this.grandFtext
};
}
};
</script>
子组件
<template>
<div class="son">
子组件
<p>{{ text }}</p>
</div>
</template>
<script>
export default {
inject: ["grandFtext"],
data() {
return {
text: this.grandFtext
};
},
};
</script>
- 效果
$ attrs和$ listeners
上述的provide和inject实现了多层级组件数据的传输,但是不能够实现子组件向祖先组件传递数据,如果要实现子传祖,可以使用$ attrs和$ listeners
官方释义:$attrs包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。 $listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
其实很好理解,也就是从父组件定义并且没有在组件中用props接收的prop,都会在$attrs中,可以将其传入子孙组件并使用,而 $listeners则包括了在父组件上的所有v-on事件监听器,将其传入子孙组件,就可以使用 $emit的方式向祖先组件传送数据。
- 示例
祖先组件
<template>
<div class="grandfather">
祖先组件
<p>{{ text }}</p> //显示子孙组件传过来的值用
<father
name="爷爷"
text="一段来自祖先组件的数据" //这一段文字稍后在父组件是没有被props接收的
@showSon="showSon"
></father>
</div>
</template>
<script>
export default {
data() {
return {
text: null
};
},
methods: {
showSon(data) {//接收子孙组件传来的数据
this.text = data;
}
}
};
</script>
父组件
<template>
<div class="father">
父组件
<p></p>
<son v-bind="$attrs" v-on="$listeners"></son>
//由于props只接受了name,所以另一个prop会在$attrs中,可以传到子组件。
//这里$listeners就包括了祖先组件定义在父组件上的事件监听@showson,传入子组件。
</div>
</template>
<script>
export default {
data() {
return {};
},
props: {
name: {
default: ""
}
},
};
</script>
子组件:
<template>
<div class="son">
子组件
<p>{{ text }}</p>
<button @click="clickEvent">向祖先传值</button>
</div>
</template>
<script>
export default {
data() {
return {
text: this.$attrs.text //使用来自祖先组件的数据
};
},
methods: {
clickEvent() {
this.$emit("showSon", "一段来自子组件的数据");
//可以使用定义在父组件上的事件监听
}
}
};
</script>
- 效果
可以看到是可以使用到祖先组件传输的数据的。
点击子组件的按钮后:
祖先组件拿到了来自子组件的数据。 - 小结
这两种方式虽然不常用,但是还是有认识的必要,因为相对比 eventBus和Vuex,会更加方便些。