寫文章不容易,點個讚唄兄弟 專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧 研究基於 Vue版本 【2.5.17】javascript
若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧html
今天咱們用白話文解讀props 的工做原理緩存
props 真的挺有用的,做爲父傳子的載體,你們確定都用過,可是你有沒有想過,Props 究竟是怎麼工做的?函數
但願先看下 響應式原理,對 props 理解頗有幫助學習
響應式原理測試
開篇以前,我提出三個問題ui
一、父組件 怎麼傳值給 子組件的 propsthis
二、子組件如何讀取propsspa
三、父組件 data 更新,子組件的props 如何更新
今天咱們帶着三個問題去開始咱們的講解
明白這三個問題,那麼相信你也就理解了 props 的工做原理
如今咱們有一個這樣的 根組件 A 和 他的 子組件 testb
根組件A 會 把 parentName 傳給 子組件 testb 的 props
根組件A 也是 組件testb 的 父組件
<div class="a" >
<testb :child-name="parentName" ></testb>
</div>
複製代碼
new Vue({
el:".a",
name:"A",
components:{
testb:{
props:{
childName:""
},
template: '<p>父組件傳入的 props 的值 {{childName}}</p>',
}
},
data(){
return {
parentName:"我是父組件"
}
},
})
複製代碼
按照上面的例子,開始咱們的問題解析
父組件怎麼傳值給子組件的 props
這部份內容會比較多,可是這部份內容是 props 的重中之重,必須理解好吧
根據上面的場景設置,testb 是一個子組件,接收一個 props(child-name)
而後 根組件 A 把 自身的 parentName 綁定到 子組件的屬性 child-name 上
父組件的模板 會被解析成一個 模板渲染函數
(function() {
with(this){
return _c('div',{staticClass:"a"},[
_c('testb',{attrs:{"child-name":parentName}})
],1)
}
})
複製代碼
這段代碼須要解釋下
雖然想不涉及源碼,可是這段代碼對咱們理解頗有幫助,並且不難,因此決定放上來
一、_c 是渲染組件的函數,_c('testb') 表示渲染 testb 這個子組件
二、由於 with 的做用是,綁定大括號內代碼的 變量訪問做用域
三、這是一個匿名自執行函數,會在後面執行
簡化上面的函數,作個例子測試一下
function test(){
with(this){ console.log(parentName) }
}
test.call({parentName:"測試名字"})
複製代碼
你能看到,我給 test 綁定了一個對象做用域,加上 with 綁定 this,而後讀取 parentName 就會從 傳入的對象上獲取
瞭解了這個,咱們來看下一步
以後,模板函數會被執行,執行時會綁定 父組件爲做用域
因此渲染函數內部全部的變量,都會從父組件對象 上去獲取
綁定了父做用域以後, parentName 天然會從父組件獲取,相似這樣
{ attrs: { child-name: parentVm.parentName } }
複製代碼
函數執行了,內部的 _c('testb') 第一個執行,而後傳入了 賦值後的 attrs
父組件賦值以後的 attrs 就是下面這樣
{ attrs: { child-name: "我是父組件" } }
複製代碼
此時,父組件就正式 利用 props 把 parentName 傳給了 子組件的props child-name
_c('testb',{attrs:{"child-name":parentName}})
複製代碼
而 attrs 包含 普通屬性 和 props,因此須要 篩選出 props,而後保存起來
props 會被 保存到 實例的_props 中,而且 會逐一複製到 實例上,而且每個屬性會被設置爲響應式的
你看到的,每個 實例都會有 一個 _props 的同時,也會把屬性直接放在 實例上。
我是不會騙你的好吧
經過上面的問題,咱們知道了 子組件保存了 父組件 傳入 的數據
prop 的數據會被 逐一複製到 vm對象上(子組件的實例 this) 上
可是複製的時候,會對每一個屬性,同時設置 get 和 set 函數,進行 訪問轉接 和 賦值轉接
下面是我簡化了源碼的一段代碼,瞭解一下
Object.defineProperty(vm, key, {
get() {
return this._props[key]
},
set(val) {
this._props[key] = val
}
});
複製代碼
我以 props 其中一個 屬性 childName 爲例好吧
Object.defineProperty(childVm, childName, {
get() {
return this._props.childName
},
set(val) {
this._props.childName = val
}
});
複製代碼
你訪問 props 其中一個值 vm.childName,其實訪問的是 vm._props.childName
你賦值 vm.childName= 5 ,實際上是賦值 vm._props.childName= 5
可是你直接在這裏給 props 賦值,你是不會影響到 父組件的data 的好吧,兩個東西徹底沒有關係
就像你老爸給錢你用,你怎麼用,對老爸都沒有影響
總結
移花接木,狸貓換太子,就是 props 本人了,掛羊頭賣狗肉,很明顯違法行爲,欺騙消費者
看過我上一篇文章的都知道
每個實例都會存在 一個 專屬watcher
一、用於實例本身更新視圖
二、用於給 依賴的屬性保存,而後屬性變化的時候,通知實例更新
我已經在 上一篇講解過 響應式原理,若是這裏你不明白,能夠查看一下
【Vue原理】響應式原理 - 白話版
以 parentName 爲例,講解更新,parentName 是 父組件的 data,而後傳給子組件的props
在 父組件渲染函數中
(function() {
with(this){
return _c('div',{staticClass:"a"},[
_c('testb',{attrs:{"child-name":parentName}})
],1)
}
})
複製代碼
由於 Vue 會對組件的渲染函數進行緩存,因此更新的時候,不須要從新解析,直接讀取緩存,會加快渲染速度
而後渲染函數執行,開啓新一輪的 props 賦值操做,回到了第一個問題,若是不記得,能夠回去看下
一、父組件 data 的值 和 子組件的 props 通常是沒有任何聯繫的,更改 props 不影響父組件 data,可是若是傳入的是 對象,那麼修改對象,是會影響父組件的,由於數據是原樣傳入的,因此修改對象,兩個地方都會影響
二、props 也是響應式的,跟 data 本質 差很少
三、props 會訪問轉接,賦值轉接 ,其實操做的是 vm._props 的屬性