深入了解Vue3中props的原理與使用
前言
props指父組件往子組件中傳入?yún)?shù),我們來(lái)介紹下如何理解vue3的props的原理
介紹
了解其原理之前我們要清楚vue的虛擬節(jié)點(diǎn)是什么,有什么表現(xiàn)。
- 虛擬節(jié)點(diǎn)主要分成兩種,分別是組件類型及元素類型,當(dāng)然還有文本類型等特殊的虛擬節(jié)點(diǎn)。
- 虛擬節(jié)點(diǎn)都會(huì)接收三個(gè)基本參數(shù),分別是type, props, children
對(duì)于組件類型而言:
type是一個(gè)對(duì)象里面包括基本的render函數(shù)及setup函數(shù)等
{
render() {
return h() // render函數(shù)返回一個(gè)虛擬節(jié)點(diǎn)
}
setup() {}
}props是父組件往子組件傳入的參數(shù)
children是父組件往子組件傳入的插槽
對(duì)于元素類型而言:
- type是當(dāng)前節(jié)點(diǎn)的元素類型,如div
- props是當(dāng)前節(jié)點(diǎn)的元素屬性,如class
- children是當(dāng)前節(jié)點(diǎn)的子元素是個(gè)數(shù)組,數(shù)組的內(nèi)容有可能是組件也有可能是元素
原理
前提
基于此我們可以創(chuàng)建兩個(gè)組件互為父子的組件分別是APP組件(父),F(xiàn)OO組件(子)
import { h } from '../h.js';
import { Foo } from './foo.js';
export const App = {
// render 頁(yè)面元素內(nèi)容即template
render() {
// 接收一個(gè)Foo,并通過(guò)h函數(shù)創(chuàng)建一個(gè)子組件node2
let node2 = h(
Foo,
{
count: 1
},
{}
)
return h(
'div',
{
id: 'root',
},
[
node2 // App接收Foo組件作為其子組件
]
);
},
setup() {
}
};import { h } from '../h.js';
// 定義一個(gè)Foo組件用于驗(yàn)證Props功能
export const Foo = {
// render 頁(yè)面元素內(nèi)容即template
render() {
// ui 頁(yè)面內(nèi)容
const foo = h(
'div',
{},
'Foo' + this.count
);
return h('div', {}, [foo]);
},
// 第一個(gè)參數(shù)props,用于父子組件傳值
setup(props) {
console.log(props.count); // 打印傳入的props值
}
};通過(guò)上面的代碼我們可以看到,這里創(chuàng)建了兩個(gè)文件分別代表父組件和子組件。
vue3的編譯過(guò)程中我們會(huì)先去解析組件,就將組件傳入patch函數(shù)中,判斷當(dāng)前的虛擬節(jié)點(diǎn)類型是組件還是元素,再走下面的編譯。
上面的父組件代碼中我可以看到對(duì)于Foo,我們創(chuàng)建了一個(gè)組件叫node2,并在props的位置中傳入了一個(gè)count: 1的props。
let node2 = h(
Foo,
{
count: 1
},
{}
)因?yàn)関ue會(huì)遞歸的去解析每一個(gè)虛擬節(jié)點(diǎn)所以這個(gè)node2最后也會(huì)被解析。!?。?/p>
下面介紹解析這個(gè)node2的時(shí)候做了什么,如何實(shí)現(xiàn)props的功能的
創(chuàng)建組件實(shí)例對(duì)象
如果是組件類型的話,將我們組件的虛擬節(jié)點(diǎn)作為參數(shù)傳入createComponentInstance, 去創(chuàng)建一個(gè)組件實(shí)例對(duì)象,如下:
export function createComponentInstance(vnode) {
const component = {
vnode,
type: vnode.type,
// 先創(chuàng)建一個(gè)空的setupState,去暫存組件類型虛擬節(jié)點(diǎn)的setup返回值
setupState: {},
// 創(chuàng)建一個(gè)props,用來(lái)存儲(chǔ)組件虛擬節(jié)點(diǎn)接收的props,注意:props不允許改變 (props)
props: {},
}
return component
}因?yàn)槲覀儎?chuàng)建vnode的時(shí)候,實(shí)際上會(huì)接收接收三個(gè)基本參數(shù),分別是type, props, children
所以這里傳入的vnode會(huì)帶有props字段,而這個(gè)props字段是count:1(細(xì)品)
假設(shè)我們?cè)谶@一步創(chuàng)建了一個(gè)組件實(shí)例對(duì)象,叫instance
初始化Props操作
因?yàn)?strong>instance就接收了vnode,而組件的vnode實(shí)際上包含了props
所以接著就會(huì)執(zhí)行一個(gè)initProps的操作,如果vnode中props存在,那么就將props掛載到instance下的props字段中
// 將傳入的props掛載到組件實(shí)例對(duì)象上
export function initProps(instance, props) {
instance.props = props
}這時(shí)候組件實(shí)例對(duì)象就可以正常的拿到props的值了
創(chuàng)建proxy對(duì)象去獲取Props
因?yàn)槲覀冎来a中我們可以通過(guò)this. 的方式去獲取props的值,而且props已經(jīng)被掛載到了組件實(shí)例對(duì)象中。
因此創(chuàng)建一個(gè)proxy對(duì)象(后續(xù)通過(guò)bind的方式將這個(gè)對(duì)象掛載到render函數(shù)等位置,this.的時(shí)候由props去映射到對(duì)應(yīng)的props中)
instance.proxy = new Proxy({ _: instance }, PublicInstanceProxyHandlers);
const PublicInstanceProxyHandlers = {
get({ _: instance }, key) {
const { setupState, props } = instance
// 如果在傳入的props中,則返回的對(duì)應(yīng)的值 (props)
if (hasOwn(props, key)) {
return props[key]
}
}
}props作為參數(shù)傳入setup
因?yàn)槲覀冎纕ue3中在setup中沒(méi)有this,但可以接收一個(gè)props,通過(guò)這個(gè)props去獲取到父組件傳入的值。
那我們已經(jīng)將props的值掛載到組件實(shí)例對(duì)象上,所以我們可以將props作為參數(shù)傳入到setup中。
const {setup} = instance.type.setup // 獲取setup函數(shù)
// 在執(zhí)行setup的時(shí)候?qū)rops傳入即可
setup(shallowReadonly(instance.props))因此我們?cè)谑褂玫臅r(shí)候就可以通過(guò)接收props在setup中讀值。
// 第一個(gè)參數(shù)props,用于父子組件傳值
setup(props) {
console.log(props.count); // 打印傳入的props值
}將proxy掛載到render上
在解析一個(gè)虛擬節(jié)點(diǎn)的時(shí)候,其實(shí)會(huì)先執(zhí)行setup函數(shù),然后再執(zhí)行render,因?yàn)槲覀兛梢酝ㄟ^(guò)this. 的方式去獲取props的值。
所以我們通過(guò)bind的方式將我們之前創(chuàng)建proxy對(duì)象掛載到render函數(shù)中,保證其this可以正確取到props的值。
instance.render.call(instance.proxy)
總結(jié)
到這里props的原理就講完了。
props實(shí)際上是 父組件往子組件的虛擬節(jié)點(diǎn)的props處插入的參數(shù)。
因此我們?cè)趧?chuàng)建子組件的組件實(shí)例對(duì)象的時(shí)候可以拿到這個(gè)props的值并將其掛載到子組件的組件實(shí)例對(duì)象中。
如果組件中需要使用props,通常是兩個(gè)位置setup或render
對(duì)于setup,我們可以將組件實(shí)例對(duì)象的props作為參數(shù)傳入,這樣就可以使用了,但是注意props是一個(gè)不能改的值,所以我們要用readonly包裹起來(lái)。
在組件的頁(yè)面中我們可以通過(guò) this. 的方式去讀取props的值,所以在渲染頁(yè)面即調(diào)用render函數(shù)的時(shí)候,我們可以通過(guò)創(chuàng)一個(gè)proxy對(duì)象,將這個(gè)對(duì)象掛載到render函數(shù)中,通過(guò)proxy去讀取到對(duì)應(yīng)的props值
到此這篇關(guān)于深入了解Vue3中props的原理與使用的文章就介紹到這了,更多相關(guān)Vue3 props內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue實(shí)現(xiàn)dom元素拖拽并限制移動(dòng)范圍的操作代碼
這篇文章主要介紹了Vue實(shí)現(xiàn)dom元素拖拽并限制移動(dòng)范圍的操作代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-12-12
vuecli3打包后出現(xiàn)跨域問(wèn)題,前端配置攔截器無(wú)效的解決
這篇文章主要介紹了vuecli3打包后出現(xiàn)跨域問(wèn)題,前端配置攔截器無(wú)效的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
vue使用screenfull插件實(shí)現(xiàn)全屏功能
這篇文章主要為大家詳細(xì)介紹了vue使用screenfull插件實(shí)現(xiàn)全屏功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
Vue Treeselect樹(shù)形下拉框的使用小結(jié)
樹(shù)形下拉框是一個(gè)帶有下列樹(shù)形結(jié)構(gòu)的下拉框,本文主要介紹了Vue Treeselect樹(shù)形下拉框的使用小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10
vue中watch和computed的區(qū)別與使用方法
這篇文章主要給大家介紹了關(guān)于vue中watch和computed的區(qū)別與使用方法的相關(guān)資料,文中通過(guò)實(shí)例代碼結(jié)束的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08

