寫文章不容易,點個讚唄兄弟 專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧 研究基於 Vue版本 【2.5.17】javascript
若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧html
今天咱們用白話文解讀props 的工做原理緩存
props 真的挺有用的,做爲父傳子的載體,你們確定都用過,可是你有沒有想過,Props 究竟是怎麼工做的?函數
但願先看下 響應式原理,對 props 理解頗有幫助學習
響應式原理測試
<br>this
開篇以前,我提出三個問題3d
一、父組件 怎麼傳值給 子組件的 propscode
二、子組件如何讀取props
三、父組件 data 更新,子組件的props 如何更新
今天咱們帶着三個問題去開始咱們的講解
明白這三個問題,那麼相信你也就理解了 props 的工做原理
<br> <br>
如今咱們有一個這樣的 根組件 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 的同時,也會把屬性直接放在 實例上。
我是不會騙你的好吧
<br> <br>
經過上面的問題,咱們知道了 子組件保存了 父組件 傳入 的數據
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 本人了,掛羊頭賣狗肉,很明顯違法行爲,欺騙消費者
<br> <br>
看過我上一篇文章的都知道
每個實例都會存在 一個 專屬watcher
一、用於實例本身更新視圖
二、用於給 依賴的屬性保存,而後屬性變化的時候,通知實例更新
我已經在 上一篇講解過 響應式原理,若是這裏你不明白,能夠查看一下
【Vue原理】響應式原理 - 白話版
以 parentName 爲例,講解更新,parentName 是 父組件的 data,而後傳給子組件的props
在 父組件渲染函數中
(function() { with(this){ return _c('div',{staticClass:"a"},[ _c('testb',{attrs:{"child-name":parentName}}) ],1) } })
由於 Vue 會對組件的渲染函數進行緩存,因此更新的時候,不須要從新解析,直接讀取緩存,會加快渲染速度
而後渲染函數執行,開啓新一輪的 props 賦值操做,回到了第一個問題,若是不記得,能夠回去看下
<br> <br>
一、父組件 data 的值 和 子組件的 props 通常是沒有任何聯繫的,更改 props 不影響父組件 data,可是若是傳入的是 對象,那麼修改對象,是會影響父組件的,由於數據是原樣傳入的,因此修改對象,兩個地方都會影響
二、props 也是響應式的,跟 data 本質 差很少
三、props 會訪問轉接,賦值轉接 ,其實操做的是 vm._props 的屬性
<br> <br>