Vue組件的實(shí)現(xiàn)原理詳細(xì)分析
渲染組件
一個(gè)組件內(nèi)部必須要使用 render 進(jìn)行渲染,且返回虛擬 DOM
這是一個(gè)最簡組件實(shí)例
const MyComponent = { // 組件名稱,可選 name: "MyComponent", // 組件的渲染函數(shù),其返回值必須為虛擬 DOM render() { // 返回虛擬 DOM return { type: "div", children: `我是文本內(nèi)容`, }; }, };
渲染器中的 mountComponent 函數(shù)完成組件的渲染
function mountComponent(vnode, container, anchor) { // 通過 vnode 獲取組件的選項(xiàng)對象,即 vnode.type const componentOptions = vnode.type; // 獲取組件的渲染函數(shù) render const { render } = componentOptions; // 執(zhí)行渲染函數(shù),獲取組件要渲染的內(nèi)容,即 render 函數(shù)返回的虛擬 const subTree = render(); // 最后調(diào)用 patch 函數(shù)來掛載組件所描述的內(nèi)容,即 subTree patch(null, subTree, container, anchor); }
組件更新
組件初始化步驟:
- 取得 data 函數(shù)后用 reactive 將其變成響應(yīng)式的
- render 函數(shù)內(nèi)將 this 指向 state,并將 state 作為第一個(gè)參數(shù)傳入 render 函數(shù)
將渲染任務(wù)包裝到一個(gè)副作用函數(shù) effect 里面,即可實(shí)現(xiàn)響應(yīng)式更新數(shù)據(jù)
若要使每次響應(yīng)式數(shù)據(jù)修改后,effect 僅執(zhí)行一次,則需要引入調(diào)度器概念
這是書中給出的最簡調(diào)度器實(shí)例
即先把 effect 放入微任務(wù)隊(duì)列,等執(zhí)行棧清空再調(diào)出來執(zhí)行
// 任務(wù)緩存隊(duì)列,set可以自動去重 const queue = new Set(); // 一個(gè)標(biāo)志,代表是否正在刷新任務(wù)隊(duì)列 let isFlushing = false; // 創(chuàng)建一個(gè)立即 resolve 的 Promise 實(shí)例 const p = Promise.resolve(); // 調(diào)度器的主要函數(shù),用來將一個(gè)任務(wù)添加到緩沖隊(duì)列中,并開始刷新隊(duì)列 function queueJob(job) { // 將 job 添加到任務(wù)隊(duì)列 queue 中 queue.add(job); // 如果還沒有開始刷新隊(duì)列,則刷新之 if (!isFlushing) { // 將該標(biāo)志設(shè)置為 true 以避免重復(fù)刷新 isFlushing = true; // 在微任務(wù)中刷新緩沖隊(duì)列 p.then(() => { try { // 執(zhí)行任務(wù)隊(duì)列中的任務(wù) queue.forEach((job) => job()); } finally { // 重置狀態(tài) isFlushing = false; queue.clear = 0; } }); } }
父子組件
這是一個(gè)簡單的父子組件代碼
// 子組件 <template> <MyComponent :title="title" /> </template> // 父組件 const vnode = { type: MyComponent, props: { title: 'A Big Title' } }
父組件更新導(dǎo)致子組件更新(被動更新)過程:
- 父組件自更新
- 渲染器檢查 subTree 發(fā)現(xiàn)存在 vnode,則調(diào)用 patchComponent 實(shí)現(xiàn)子組件更新
setup函數(shù)
setup 函數(shù)為配合組合式 API 所引入的
他有如下兩種返回值形式
// 返回函數(shù) const comp = { setup() { return () => { return { type: "div", children: "give up for vuejs", }; }; }, }; // 返回對象 const comp = { setup() { const count = ref(0); return { count, }; }, render() { return { type: "div", children: `count is ${this.count}`, }; }, };
setup 接收兩個(gè)參數(shù),分別是 props 以及 setupContext
setupContext 包含以下四個(gè)主要對象
- slots 插槽
- emit 自定義事件
- attrs 自定義屬性
- expose 暴露
emit 實(shí)現(xiàn)
只需要實(shí)現(xiàn)一個(gè) emit 函數(shù)并將其添加到 setupContext 對象中
到此這篇關(guān)于Vue組件的實(shí)現(xiàn)原理詳細(xì)分析的文章就介紹到這了,更多相關(guān)Vue組件實(shí)現(xiàn)原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
談?wù)剬ue響應(yīng)式數(shù)據(jù)更新的誤解
本篇文章主要介紹了談?wù)剬ue響應(yīng)式數(shù)據(jù)更新的誤解,深入了解了vue響應(yīng)式數(shù)據(jù),有興趣的可以了解一下2017-08-08element-ui中el-cascader動態(tài)加載和默認(rèn)值詳解
vue+elementUI項(xiàng)目中el-cascader級聯(lián)選擇器使用頻率非常高,下面這篇文章主要給大家介紹了關(guān)于element-ui中el-cascader動態(tài)加載和默認(rèn)值的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05Vue自定義復(fù)制指令 v-copy功能的實(shí)現(xiàn)
這篇文章主要介紹了Vue自定義復(fù)制指令 v-copy,使用自定義指令創(chuàng)建一個(gè)點(diǎn)擊復(fù)制文本功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01vue-router路由與頁面間導(dǎo)航實(shí)例解析
vue-router 是一個(gè)插件,需要在 Vue 的全局引用中通過 Vue.use()將它引用到 Vue 實(shí)例當(dāng)中。接下來通過本文給大家分享vue-router路由與頁面間導(dǎo)航,需要的朋友參考下吧2017-11-11