官方api有這樣一句話:這對選項需要一起使用,以允許一個祖先元件向其所有子孫後代注入一個依賴,不論元件層次有多深,並在起上下游關係成立的時間裡始終生效。平常我們的全域性狀態管理通通都交給
Vuex
來,Vuex
也的確是非常好的工具,並被官方作為指定的狀態管理器。今天給大家介紹有個新的思路進行狀態管理。可能大家對provide / inject
這對api
有點陌生,的確也是,平常開發中我們基本也不會用到。
看圖片可以知道,provide
期望傳入一個Object
,而inject
可以接受的值包括(1)一個字串陣列
(2)一個物件。程式碼如下:(最簡單的寫法)
// 父元件 App.vue
export default {
name: 'App',
provide: {
parentKey: 'aaa'
}
}
複製程式碼
// 子元件 chidlren.vue
export default {
inject: ['parentKey'],
created () {
console.log(this.parentKey)
}
}
複製程式碼
在列印臺可以看到aaa被輸出了出來,既然inject
期望值是個陣列,那應該也可以這樣
// 父元件 App.vue
export default {
name: 'App',
provide: {
parentKey: { a: 'haha' },
parentKey2: [1, 2]
}
}
複製程式碼
// 子元件 chidlren.vue
export default {
inject: ['parentKey', 'parentKey2'],
created () {
console.log(this.parentKey, this.parentKey2)
}
}
複製程式碼
之前我們傳遞是個字串,發現其實傳遞什麼都可以,對應的物件和陣列都列印出來了。 如果僅僅只是這樣,好像也沒什麼。看到api有這樣一句話:
提示:
provide
和inject
繫結並不是可響應的。這是刻意為之的。然而,如果你傳入了一個可監聽的物件,那麼其物件的屬性還是可響應的。
我們可以試下:
// 父元件 App.vue
<template>
<div class="app">
<router-view></router-view>
<button @click="changeKey"> 按鈕</button>
</div>
</template>
export default {
provide () {
return {
parentKey: this.key
}
},
methods: {
changeKey () {
this.key.push(2)
}
},
data () {
return {
key: [1]
}
}
}
複製程式碼
// 子元件 chidlren.vue
export default {
inject: ['parentKey'],
created () {
let afterKey = JSON.stringify(this.parentKey)
let timer = setInterval(() => {
console.log(this.parentKey)
if (afterKey !== JSON.stringify(this.parentKey)) clearInterval(timer)
}, 1000)
}
}
複製程式碼
最後可以看見當點選按鈕之後,在子元件chidlren.vue
中輸出的值變化了,定時器也停止了。
這裡面有幾個要注意的地方
(1). 這時候provide
必須為一個工廠函式,如果你是這樣寫的provide: {parentKey: this.key}
也就是跟之前這種寫法,控制檯會報未定義key的錯誤
(2)不要傳字串之類的值過去,比如:parentKey: this.key
而你在data
中是這樣定義key
的key: 'aaa
,提示下,他並不是一個可響應的資料,你可能會說,那不對啊,我在當前元件改變這個值,模板裡輸出的也會變啊。這時候其實可響應的值是this
當前元件
(3)大家不要試圖替換陣列來響應(為什麼說這條,因為不注意我也犯了這個錯誤 :)
(4)一旦注入了某個資料,比如上面示例中的 parentKey
,那這個元件中就不能再宣告 parentKey
這個資料了,因為它已經被父級佔有)
注意:在變異 (不是替換) 物件或陣列時,舊值將與新值相同,因為它們的引用指向同一個物件/陣列。Vue 不會保留變異之前值的副本。(來源Vue官網)
好像說了這麼久,沒說到與標題相關的。:)-- 接下來久介紹下構建全域性狀態管理的思路
// 父元件(也可以說是根元件) App.vue
export default {
name: 'App',
provide () {
return {
app: this
}
},
methods: {
changeKey () {
this.key.push(2)
}
},
data () {
return {
key: [1],
transitionName: 'slide-right'
}
}
}
複製程式碼
// 子元件 chidlren.vue
export default {
inject: ['app'],
created () {
console.log(this.app)
console.log(this.app.key)
this.app.changeKey()
}
}
複製程式碼
這樣你就可以拿到根節點app
所有的東西了,還可以訪問他的方法。以此將根節點作為狀態管理器。
如果你覺得這樣狀態多起來,十分難管理,你可以使用混合mixins
,將不同的邏輯分開到不同的 js 檔案裡。當然這種事是仁者見仁智者見智,你可以使用this.$root
訪問根節點,還可以掛載在Vue.prototype
的原型上。哈哈,這些方法是不是感覺有點邪門歪道的感覺。所以官網有這麼一句話:
provide 和 inject 主要為高階外掛/元件庫提供用例。並不推薦直接用於應用程式程式碼中。
給大家介紹下這個網站dev.iviewui.com,這個網站就是使用此方法做出來的,這樣減少了Vuex
的依賴使用vue
本身作為狀態管理器,當然,如果你的網站很大,還是建議使用Vuex
。
這對api還有很多東西可以挖掘的,比如使用ES2015的Symbol
作為唯一值,inject
中可以使用default
作為預設值等等。用法還是同學們去看看官網。這次久到此為止,清明放假了,還是休息休息。:)
如有錯誤,歡迎指出。