使用 provide/inject ,只需要向后代注入组件本身(this),后代组件中可以无视层级任意访问祖先组件中的状态。
当然它也有缺点:因为 provide/inject 中变量的修改是无法控制的。换句话说,不知道是哪个组件修改了这个全局状态
Vue 的设计理念借鉴了 React 中的单向数据流原则(虽然有 sync 这种破坏单向数据流的家伙),而 provide/inject 明显破坏了单向数据流原则。试想,如果有多个后代组件同时依赖于一个祖先组件提供的状态,那么只要有一个组件修改了该状态,那么所有组件都会受到影响。这一方面增加了耦合度,另一方面,使得数据变化不可控。如果在多人协作开发中,这将成为一个噩梦。
下面我们来看看一个小案列:
我的四个组件 App.vue(祖组件) App.vue下面有一个Navbar.vue 和一个Tabbar.vue 而Tabbar.vue组件下有一个TabbarItem.vue的组件
现在要实现的的功能是在TabbarItem.vue组件中改变Navbar.vue组件中的值
App.vue
html
<template>
<div>
<Navbar :nvartitle="nvaTitle"></Navbar>
<Tabbar></Tabbar>
</div>
</template>
<script>
import Navbar from "./components/Navbar.vue" //导入AChild组件模板
import Tabbar from "./components/Tabbar.vue";
export default {
inheritAttrs: false,
data() {
return {
nvaTitle:"首页"
}
},
components: {
Navbar,
Tabbar
},
provide(){
return{
myNvarTitle:this.nvaTitle, //向外提供一个值(可以供其他组件可以直接获取到)
app:this, //向外提供一个值,这个值的名称是我们自己定义的,this表示当前根组件对象(可以供其他组件可以直接获取到)
appMythod:this.MyAppMethod //向外提供一个方法。
}
},
methods: {
MyAppMethod(){
console.log("我的根组件中的方法")
}
}
}
</script>
<style>
#app{
width: 100%;
max-width: 95%;
}
* {
margin: 0px;
padding: 0px
}
ul {
list-style: none;
}
body{
display:block
}
</style>
Navbar.vue
html
<template>
<div>
<button>返回</button>
<span>{{app.nvaTitle}}</span>
<button>首页</button>
</div>
</template>
<script>
export default {
props:["nvartitle"],
inject:["myNvarTitle","app"],//在App.vue根组件中通过provide向外提供了一个myNvarTitle,和app的值,我们可以通过注入的方式获取
components: {
}
}
</script>
<style scoped>
div {
display: flex;
width: 100%;
justify-content: space-between;
height: 50px;
line-height: 50px;
background: gray;
}
</style>
Tabbar.vue
html
<template>
<ul>
<TabbarItem v-for="item in datalist" :key="item" :itemStr="item"></TabbarItem>
</ul>
</template>
<script>
import TabbarItem from "./TabbarItem.vue"
export default {
data() {
return {
datalist: ["首页", "列表", "我的"]
}
},
components: {
TabbarItem
}
}
</script>
<style scoped>
ul {
display: flex;
position: fixed;
bottom: 0;
width: 100%;
height: 50px;
line-height: 50px;
}
li {
flex: 1;
text-align: center;
}
</style>
TabbarItem.vue
html
<template>
<li @click="handelClick">
{{ itemStr }}
</li>
</template>
<script >
export default {
props: ["itemStr"],
inject: ["app","appMythod"],//在App.vue根组件中通过provide向外提供了一个app的值和一个appMythod的方法,我们可以通过注入的方式获取
methods: {
handelClick() {
this.app.nvaTitle = this.itemStr //这个app就是根组件,根组件中有一个nvaTitle的对象,我们可以重新给他赋值,它的值变化后就会自动流向需要这个值的子组件。
this.appMythod(); //直接调用跟组件中的方法。
}
}
}
</script>