Vue provide/inject 部分原始碼分析 實現響應式資料更新
下面是我自己曾經遇到 一個問題,直接以自己QA的形式來寫吧
自問自答了,需要的同學也可以直接訪問 ofollow,noindex">segmentfault地址
官網給出例項,說本身是不支援資料響應式的, 但是可以傳入響應式資料,那麼provide,inject就可以實現響應式。
我這裡理解應該沒錯哈,有不對的地方請指出。
我自己寫的demo,做了如下更改
parent 頁面:
export default { provide(){ return{foo:this.fonnB} }, data(){ return {fonnB:'old word'} } created() { setTimeout(()=>{ this.fonnB="new words";// 這種跟新,僅僅foonB變化了,foo沒有變化 this._provided.foo="new words"; //這種更新 foo變化了,但子元件獲得的foo依舊是old words console.log( this._provided) },1000) }, }
child頁面:
export default { inject:['foo'], data(){ return {chilrfoo:this.foo} } } 通過上面2個方法,經過驗證,子元件頁面都沒辦法實現響應更新this.foo的值。 求解釋,謝謝 以上是我自己的問題, 下面是我基本理解後,在自己回答的問題
現做了如下修改,可以達到父親元件改變,下面的孫子元件都能更新資料.這樣就是傳入了一個響應式資料,如果需要雙向資料的話,需要在child頁面的computed 中手動寫set 函式,computed 本身就只相當於一個get函式。
值得注意是:child頁面data 資料中childfooOld並不會響應。這個點還沒搞懂。
parent頁面:
export default {
provide(){ return{foo:this.fonnB} }, data(){ return { fonnB:{a:'old word'} } } created() { setTimeout(()=>{ this.fonnB.a="new words"; //這種更新 foo變化了,但子元件獲得的foo依舊是old words },1000) }, }
child頁面:
export default { inject:['foo'], data(){ return { childfooOld:this.foo.a } }, computed:{ chilrfoo(){ returnthis.foo.a } } }
關於prodive 和inject 原始碼部分如下
export function initInjections (vm: Component) {
const result = resolveInject(vm.$options.inject, vm)
if (result) {
observerState.shouldConvert = false Object.keys(result).forEach(key => { defineReactive(vm, key, result[key]) }) observerState.shouldConvert = true
}
}
可以看出 prodive 也運用了defineReactive 函式,增加了自身的set,get函式,也是響應式資料,如下圖
如下 是inject 原始碼,我沒看出來那裡明確增加了set/get,但是打印出來結果inject 也是有set/get的
export function resolveInject (inject: any, vm: Component): ?Object {
if (inject) {
// inject 是 :any 型別因為流沒有智慧到能夠指出快取 const result = Object.create(null) // 獲取 inject 選項的 key 陣列 const keys = hasSymbol ? Reflect.ownKeys(inject).filter(key => { /* istanbul ignore next */ return Object.getOwnPropertyDescriptor(inject, key).enumerable }) : Object.keys(inject) for (let i = 0; i < keys.length; i++) { const key = keys[i] const provideKey = inject[key].from let source = vm while (source) { if (source._provided && provideKey in source._provided) { result[key] = source._provided[provideKey] break } source = source.$parent } if (!source) { if ('default' in inject[key]) { const provideDefault = inject[key].default result[key] = typeof provideDefault === 'function' ? provideDefault.call(vm) : provideDefault } else if (process.env.NODE_ENV !== 'production') { warn(`Injection "${key}" not found`, vm) } } } return result
}
}
通過computed 就實現了上下傳值,個人疑問就是
child頁面,直接把foo 繫結到data屬性下,foo變化時,child中的data不變化。。 按道理,data中有get/set ,應該也是響應的,求大神分享