vue3源碼剖析之簡(jiǎn)單實(shí)現(xiàn)方法
前言
最近,由于我的第一個(gè)vue3 + ts的正式項(xiàng)目,已經(jīng)進(jìn)入驗(yàn)收階段。聽(tīng)你們老說(shuō)vue3、vue3的,我就想著去看看vue3到底和vue2有啥區(qū)別。🤷🏻♀️🤷🏻♀️🤷🏻♀️
文章主要闡述vue3的API用法,以及簡(jiǎn)單地實(shí)現(xiàn)一個(gè)vue3。帶大家感受一下vue3與之前vue2的區(qū)別。以及簡(jiǎn)單帶大家揭秘源碼中vue3初始化的一個(gè)流程。
🍹準(zhǔn)備工作
要想看看vue3內(nèi)部的源碼是咋搞得,首先跟vue2源碼剖析一樣,先從github上下一份源碼到本地。
接著就是安裝依賴:
yarn --ignore-scripts
在你執(zhí)行命令的時(shí)候可能會(huì)遇到node版本過(guò)低的錯(cuò)誤:
解決此問(wèn)題可以升級(jí)自己的node版本,或者忽略該engine。
如果選擇忽略的話可以設(shè)置
yarn config set --ignore-engines true
然后執(zhí)行依賴安裝。
依賴安裝完成后,編譯打包生成vuejs文件:
yarn dev
需要調(diào)試的話,可以在packages\vue\examples文件下建立測(cè)試文件。引用打包后的vue文件,可以應(yīng)用packages\vue\dist\vue.global.js。
🍲vue3用法
vue3的特性我就不多闡述了,就vue3的用法而言,更傾向于函數(shù)式編程,通過(guò)對(duì)外暴露Vue中的createApp()API,以工廠函數(shù)的方式創(chuàng)建了一個(gè)應(yīng)用程序?qū)嵗O啾容^vue2的new Vue實(shí)例,更加貼切。
在源碼文件中,我們新建一個(gè)init.html文件。
<script src="../dist/vue.global.js"></script> <body> <div id="app">{{name}}</div> <script> const { createApp } = Vue const app1 = createApp({ data() { return { name: 'clying' } }, setup() { return { name: 'deng' } } }).mount('#app') </script> </body>
根據(jù)上例,我們可以看出vue3是即支持Composition API,也支持Options API,兩者可以同時(shí)使用。
但是,我們可以看到在data和setup中,我同時(shí)使用了一個(gè)name變量進(jìn)行賦值。那么頁(yè)面中會(huì)展示哪一個(gè)呢?
3!2!1!上答案:
可以明顯看出composition-api中setup優(yōu)先級(jí)更高。
當(dāng)然也可以在源碼中的packages\runtime-core\src\componentPublicInstance.ts看到,通過(guò)switch先判斷setup中的變量是否存在,然后再去判斷data中的變量。所以setup中變量的優(yōu)先級(jí)會(huì)高于data中的變量。
🍖實(shí)現(xiàn)
通過(guò)上面的用法,我們可以知道vue3中會(huì)對(duì)外暴露一個(gè)Vue變量,內(nèi)部存在createApp、reactive等方法。
在此,我們先實(shí)現(xiàn)vue3的初始化框架。就createApp而言,它會(huì)接收用戶傳入的參數(shù):data()、setup()等,最后進(jìn)行實(shí)例掛載mount。所以在createApp中會(huì)接收一些參數(shù)options、內(nèi)部還會(huì)存在mount方法。
const Vue = { createApp(options) { return { mount(selector) { //解析、獲取render、掛載 } } } }
在mount中通過(guò)selector獲取到宿主元素。
接下來(lái)就是對(duì)模板的編譯,由于將template編譯AST后,依舊要轉(zhuǎn)成render函數(shù)。在此我們簡(jiǎn)化操作,在編譯時(shí)直接返回一個(gè)render。
mount(selector) { //解析、獲取render、掛載 const parent = document.querySelector(selector) console.log(parent); if (!options.render) { // 編譯返回render options.render = this.compileToFunction(parent.innerHTML) } }, compileToFunction(template) { return function render() { const h = document.createElement('div') h.textContent = this.name return h } }
拿到render之后,執(zhí)行它,將其添加到宿主元素中,將老的節(jié)點(diǎn)刪除。
在執(zhí)行render的時(shí)候,我們需要注意它的this指向。如果給它綁定data,那么它展示的就會(huì)使data中的name。
mount(selector) { //解析、獲取render、掛載 const parent = document.querySelector(selector) console.log(parent); if (!options.render) { // 編譯返回render options.render = this.compileToFunction(parent.innerHTML) } // 執(zhí)行render const el = options.render.call(options.data()) parent.innerHTML = '' parent.appendChild(el) },
可以看到頁(yè)面上展示的是clying。反之,如果綁定的是options.setup(),那么頁(yè)面上出現(xiàn)的就是deng。
對(duì)于vue3的用法,我們知道setup的優(yōu)先級(jí)是高于data的。那我們可以使用代理啊,將兩者的屬性變量,通過(guò)代理的方式,糅合到一起,優(yōu)先考慮setup。當(dāng)訪問(wèn)相同name時(shí),實(shí)際訪問(wèn)的就是setup中的name。
mount(selector) { //解析、獲取render、掛載 const parent = document.querySelector(selector) console.log(parent); if (!options.render) { // 編譯返回render options.render = this.compileToFunction(parent.innerHTML) } if (options.setup) { this.setupState = options.setup() } if (options.data) { this.data = options.data() } this.proxy = new Proxy(this, { get(target, key) { if (key in target.setupState) { return target.setupState[key] } else if (key in target.data) { return target.data[key] }// 還可能存在props、watch等其他同名變量 }, set(target, key, value, newVal) { console.log(target, key, value, newVal); } }) // 執(zhí)行render this.proxy就是整合setup和data的上下文 const el = options.render.call(this.proxy) console.log(el, options.render); parent.innerHTML = '' parent.appendChild(el) },
在proxy的get中,先看setup中是否存在目標(biāo)屬性,如果存在的話返回的就是setup中的屬性變量,否則就是data中的。在渲染的時(shí)候,直接將整合的變量集傳入即可。當(dāng)然proxy中也會(huì)存在set方法,需要先代理,然后在外部獲取變量做值得修改才能觸發(fā),在此有興趣的同學(xué)可以自行研究哦!
總結(jié)
到此這篇關(guān)于vue3源碼剖析之簡(jiǎn)單實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue3源碼剖析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue+Element實(shí)現(xiàn)動(dòng)態(tài)生成新表單并添加驗(yàn)證功能
這篇文章主要介紹了Vue+Element實(shí)現(xiàn)動(dòng)態(tài)生成新表單并添加驗(yàn)證功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05Vite+Electron快速構(gòu)建VUE3桌面應(yīng)用的實(shí)現(xiàn)
本文主要介紹了Vite+Electron快速構(gòu)建VUE3桌面應(yīng)用的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10在Vue中實(shí)現(xiàn)網(wǎng)頁(yè)截圖與截屏功能詳解
在Web開(kāi)發(fā)中,有時(shí)候需要對(duì)網(wǎng)頁(yè)進(jìn)行截圖或截屏,Vue作為一個(gè)流行的JavaScript框架,提供了一些工具和庫(kù),可以方便地實(shí)現(xiàn)網(wǎng)頁(yè)截圖和截屏功能,本文將介紹如何在Vue中進(jìn)行網(wǎng)頁(yè)截圖和截屏,需要的朋友可以參考下2023-06-06Vue開(kāi)發(fā)實(shí)現(xiàn)吸頂效果的示例代碼
這篇文章主要介紹了Vue開(kāi)發(fā)實(shí)現(xiàn)吸頂效果的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08Nuxt3項(xiàng)目搭建過(guò)程(Nuxt3+element-plus+scss詳細(xì)步驟)
這篇文章主要介紹了Nuxt3項(xiàng)目搭建(Nuxt3+element-plus+scss詳細(xì)步驟),本次記錄一次使用Nuxt3搭建前端項(xiàng)目的過(guò)程,內(nèi)容包含Nuxt3的安裝,基于Vite腳手架(默認(rèn))構(gòu)建的vue3項(xiàng)目,element-plus的安裝配置,scss的安裝,目錄結(jié)構(gòu)的創(chuàng)建和解釋?zhuān)枰呐笥芽梢詤⒖枷?/div> 2022-12-12VueCLI通過(guò)process.env配置環(huán)境變量的實(shí)現(xiàn)
本文主要介紹了VueCLI通過(guò)process.env配置環(huán)境變量的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Vue使用sign-canvas實(shí)現(xiàn)在線手寫(xiě)簽名的實(shí)例
sign-canvas?一個(gè)基于?canvas?開(kāi)發(fā),封裝于?Vue?組件的通用手寫(xiě)簽名板(電子簽名板),支持?pc?端和移動(dòng)端,本文給大家分享Vue使用sign-canvas實(shí)現(xiàn)在線手寫(xiě)簽名,感興趣的朋友一起看看吧2022-05-05最新評(píng)論