深入了解Vue3中props的原理與使用
前言
props指父組件往子組件中傳入?yún)?shù),我們來介紹下如何理解vue3的props的原理
介紹
了解其原理之前我們要清楚vue的虛擬節(jié)點是什么,有什么表現(xiàn)。
- 虛擬節(jié)點主要分成兩種,分別是組件類型及元素類型,當然還有文本類型等特殊的虛擬節(jié)點。
- 虛擬節(jié)點都會接收三個基本參數(shù),分別是type, props, children
對于組件類型而言:
type是一個對象里面包括基本的render函數(shù)及setup函數(shù)等
{ render() { return h() // render函數(shù)返回一個虛擬節(jié)點 } setup() {} }
props是父組件往子組件傳入的參數(shù)
children是父組件往子組件傳入的插槽
對于元素類型而言:
- type是當前節(jié)點的元素類型,如div
- props是當前節(jié)點的元素屬性,如class
- children是當前節(jié)點的子元素是個數(shù)組,數(shù)組的內(nèi)容有可能是組件也有可能是元素
原理
前提
基于此我們可以創(chuàng)建兩個組件互為父子的組件分別是APP組件(父),F(xiàn)OO組件(子)
import { h } from '../h.js'; import { Foo } from './foo.js'; export const App = { // render 頁面元素內(nèi)容即template render() { // 接收一個Foo,并通過h函數(shù)創(chuàng)建一個子組件node2 let node2 = h( Foo, { count: 1 }, {} ) return h( 'div', { id: 'root', }, [ node2 // App接收Foo組件作為其子組件 ] ); }, setup() { } };
import { h } from '../h.js'; // 定義一個Foo組件用于驗證Props功能 export const Foo = { // render 頁面元素內(nèi)容即template render() { // ui 頁面內(nèi)容 const foo = h( 'div', {}, 'Foo' + this.count ); return h('div', {}, [foo]); }, // 第一個參數(shù)props,用于父子組件傳值 setup(props) { console.log(props.count); // 打印傳入的props值 } };
通過上面的代碼我們可以看到,這里創(chuàng)建了兩個文件分別代表父組件和子組件。
vue3的編譯過程中我們會先去解析組件,就將組件傳入patch函數(shù)中,判斷當前的虛擬節(jié)點類型是組件還是元素,再走下面的編譯。
上面的父組件代碼中我可以看到對于Foo,我們創(chuàng)建了一個組件叫node2,并在props的位置中傳入了一個count: 1的props。
let node2 = h( Foo, { count: 1 }, {} )
因為vue會遞歸的去解析每一個虛擬節(jié)點所以這個node2最后也會被解析。?。。?/p>
下面介紹解析這個node2的時候做了什么,如何實現(xiàn)props的功能的
創(chuàng)建組件實例對象
如果是組件類型的話,將我們組件的虛擬節(jié)點作為參數(shù)傳入createComponentInstance, 去創(chuàng)建一個組件實例對象,如下:
export function createComponentInstance(vnode) { const component = { vnode, type: vnode.type, // 先創(chuàng)建一個空的setupState,去暫存組件類型虛擬節(jié)點的setup返回值 setupState: {}, // 創(chuàng)建一個props,用來存儲組件虛擬節(jié)點接收的props,注意:props不允許改變 (props) props: {}, } return component }
因為我們創(chuàng)建vnode的時候,實際上會接收接收三個基本參數(shù),分別是type, props, children
所以這里傳入的vnode會帶有props字段,而這個props字段是count:1(細品)
假設(shè)我們在這一步創(chuàng)建了一個組件實例對象,叫instance
初始化Props操作
因為instance就接收了vnode,而組件的vnode實際上包含了props
所以接著就會執(zhí)行一個initProps的操作,如果vnode中props存在,那么就將props掛載到instance下的props字段中
// 將傳入的props掛載到組件實例對象上 export function initProps(instance, props) { instance.props = props }
這時候組件實例對象就可以正常的拿到props的值了
創(chuàng)建proxy對象去獲取Props
因為我們知道代碼中我們可以通過this. 的方式去獲取props的值,而且props已經(jīng)被掛載到了組件實例對象中。
因此創(chuàng)建一個proxy對象(后續(xù)通過bind的方式將這個對象掛載到render函數(shù)等位置,this.的時候由props去映射到對應(yīng)的props中)
instance.proxy = new Proxy({ _: instance }, PublicInstanceProxyHandlers); const PublicInstanceProxyHandlers = { get({ _: instance }, key) { const { setupState, props } = instance // 如果在傳入的props中,則返回的對應(yīng)的值 (props) if (hasOwn(props, key)) { return props[key] } } }
props作為參數(shù)傳入setup
因為我們知道vue3中在setup中沒有this,但可以接收一個props,通過這個props去獲取到父組件傳入的值。
那我們已經(jīng)將props的值掛載到組件實例對象上,所以我們可以將props作為參數(shù)傳入到setup中。
const {setup} = instance.type.setup // 獲取setup函數(shù) // 在執(zhí)行setup的時候?qū)rops傳入即可 setup(shallowReadonly(instance.props))
因此我們在使用的時候就可以通過接收props在setup中讀值。
// 第一個參數(shù)props,用于父子組件傳值 setup(props) { console.log(props.count); // 打印傳入的props值 }
將proxy掛載到render上
在解析一個虛擬節(jié)點的時候,其實會先執(zhí)行setup函數(shù),然后再執(zhí)行render,因為我們可以通過this. 的方式去獲取props的值。
所以我們通過bind的方式將我們之前創(chuàng)建proxy對象掛載到render函數(shù)中,保證其this可以正確取到props的值。
instance.render.call(instance.proxy)
總結(jié)
到這里props的原理就講完了。
props實際上是 父組件往子組件的虛擬節(jié)點的props處插入的參數(shù)。
因此我們在創(chuàng)建子組件的組件實例對象的時候可以拿到這個props的值并將其掛載到子組件的組件實例對象中。
如果組件中需要使用props,通常是兩個位置setup或render
對于setup,我們可以將組件實例對象的props作為參數(shù)傳入,這樣就可以使用了,但是注意props是一個不能改的值,所以我們要用readonly包裹起來。
在組件的頁面中我們可以通過 this. 的方式去讀取props的值,所以在渲染頁面即調(diào)用render函數(shù)的時候,我們可以通過創(chuàng)一個proxy對象,將這個對象掛載到render函數(shù)中,通過proxy去讀取到對應(yīng)的props值
到此這篇關(guān)于深入了解Vue3中props的原理與使用的文章就介紹到這了,更多相關(guān)Vue3 props內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析vue3響應(yīng)式數(shù)據(jù)與watch屬性
這篇文章主要介紹了vue3響應(yīng)式數(shù)據(jù)與watch屬性的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05vue如何解決el-select下拉框顯示ID不顯示label問題
這篇文章主要介紹了vue如何解決el-select下拉框顯示ID不顯示label問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06在 vue-cli v3.0 中使用 SCSS/SASS的方法
關(guān)于如何在 vue-cli v3.0 中使用 SCSS/SASS,這里提供三種方案。感興趣的朋友通過本文一起學習吧2018-06-06