【Vue原理】Props - 白話版

寫文章不容易,點個讚唄兄弟 專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧 研究基於 Vue版本 【2.5.17】javascript

若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧html

【Vue原理】Props - 白話版java

今天咱們用白話文解讀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 的重中之重,必須理解好吧

一、props 傳值的設置

根據上面的場景設置,testb 是一個子組件,接收一個 props(child-name)

而後 根組件 A 把 自身的 parentName 綁定到 子組件的屬性 child-name 上

在這裏插入圖片描述

二、props 父傳子前

父組件的模板 會被解析成一個 模板渲染函數

(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 就會從 傳入的對象上獲取

瞭解了這個,咱們來看下一步

三、props 開始賦值

以後,模板函數會被執行,執行時會綁定 父組件爲做用域

因此渲染函數內部全部的變量,都會從父組件對象 上去獲取

綁定了父做用域以後, parentName 天然會從父組件獲取,相似這樣

{ attrs: { child-name: parentVm.parentName } }

複製代碼

函數執行了,內部的 _c('testb') 第一個執行,而後傳入了 賦值後的 attrs

父組件賦值以後的 attrs 就是下面這樣

{ attrs: { child-name: "我是父組件" } }
複製代碼

此時,父組件就正式 利用 props 把 parentName 傳給了 子組件的props child-name

四、子組件保存 props
_c('testb',{attrs:{"child-name":parentName}})
複製代碼

而 attrs 包含 普通屬性 和 props,因此須要 篩選出 props,而後保存起來

五、子組件 設置響應式 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 本人了,掛羊頭賣狗肉,很明顯違法行爲,欺騙消費者



父組件數據變化,子組件props如何更新

看過我上一篇文章的都知道

每個實例都會存在 一個 專屬watcher

這個watcher 的做用

一、用於實例本身更新視圖

二、用於給 依賴的屬性保存,而後屬性變化的時候,通知實例更新

我已經在 上一篇講解過 響應式原理,若是這裏你不明白,能夠查看一下

【Vue原理】響應式原理 - 白話版

以 parentName 爲例,講解更新,parentName 是 父組件的 data,而後傳給子組件的props

parentName 會收集 父組件的 watcher

在 父組件渲染函數中

(function() {    

    with(this){  

        return _c('div',{staticClass:"a"},[

            _c('testb',{attrs:{"child-name":parentName}})

        ],1)

    }

})
複製代碼
TIP

由於 Vue 會對組件的渲染函數進行緩存,因此更新的時候,不須要從新解析,直接讀取緩存,會加快渲染速度

而後渲染函數執行,開啓新一輪的 props 賦值操做,回到了第一個問題,若是不記得,能夠回去看下



總結

一、父組件 data 的值 和 子組件的 props 通常是沒有任何聯繫的,更改 props 不影響父組件 data,可是若是傳入的是 對象,那麼修改對象,是會影響父組件的,由於數據是原樣傳入的,因此修改對象,兩個地方都會影響

二、props 也是響應式的,跟 data 本質 差很少

三、props 會訪問轉接,賦值轉接 ,其實操做的是 vm._props 的屬性

公衆號
相關文章
相關標籤/搜索