最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Vue Vapor 的應(yīng)用初始化

 更新時間:2026年06月17日 09:15:41   作者:Cobyte  
本文深入解析VueVaporr與Vue3在組件和虛擬DOM機制上的差異,探討VueVapor如何通過直接操作DOM提升性能,同時并重構(gòu)代碼結(jié)構(gòu)以適應(yīng)未來升級,感興趣的可以了解一下

前言

在 SolidJS 中所謂組件只是代碼的一種組件方式,在程序初始化后就不再存在了,因為它的更新不再依賴于組件。但在 Vue Vapor 中因為需要兼容原來 Vue3 的 API,所以還是必須存在組件這個概念。

Vue3 應(yīng)用初始化的核心邏輯

在 Vue3 中一般我們寫了一個組件之后,通過下面的方式進行調(diào)用的:

const app = createApp(App)
app.mount("#app")

在 createApp 函數(shù)內(nèi)部主要的過程就是把我們寫的組件生成一個虛擬 DOM,然后再通過渲染器把虛擬 DOM 進行渲染到頁面上。接下來我們需要去了解渲染器相關(guān)的知識。

reateApp 函數(shù)是渲染器返回的一個方法,主要是創(chuàng)建一個 Vue3 應(yīng)用實例。渲染器(renderer)是通過 createRenderer 函數(shù)創(chuàng)建,createRenderer 函數(shù)主要返回一個渲染器對象。createRender 函數(shù)基本結(jié)構(gòu)如下:

// 創(chuàng)建渲染器
function createRenderer(options) {
    // 渲染函數(shù),主要是把一個虛擬 DOM 渲染到某一個元素節(jié)點上
    function render(vnode, container) {
        // 具體通過 patch 函數(shù)進行渲染
        patch(null, vnode, container, null, null)
    }
    // 補丁函數(shù)
    function patch(n1, n2, container) {
		// 根據(jù)虛擬DOM 的類型不同進行不同的操作
    }
    // 返回渲染器對象
    return {
        createApp: createAppAPI(render)
    }
}

渲染器的作用就是把虛擬DOM 渲染為真實DOM,所以渲染器需要把我們寫的那些元素進行創(chuàng)建、刪除、修改和元素屬性的創(chuàng)建、刪除、修改。那么不同的平臺,對元素操作的 API 都不一樣,所以在執(zhí)行 createRenderer 函數(shù)的時候,就需要根據(jù)不同平臺對元素操作特性 API 來創(chuàng)建渲染器。我們平時一般用到的都是 Vue3 默認提供的 runtime-dom 這個包來創(chuàng)建的渲染器(renderer),runtime-dom 包就是根據(jù)瀏覽器的對元素操作的特有的DOM API 進行創(chuàng)建渲染器。runtime-dom 創(chuàng)建渲染器的主要過程如下:

// 創(chuàng)建元素
function createElement(type) {
    return document.createElement(type)
}
// 插入元素
function insert(child, parent, anchor) {
    parent.insertBefore(child, anchor || null)
}
// 創(chuàng)建元素文本
function setElementText (el, text) {
    el.textContent = text
}
// 創(chuàng)建渲染器
const renderer = createRenderer({
    createElement,
    insert,
    setElementText
})
// 創(chuàng)建 Vue3 應(yīng)用
export function createApp(...args) {
    return renderer.createApp(...args)
}

從上面的代碼我們可以看到創(chuàng)建渲染器的時候是把操作原生 DOM 的創(chuàng)建元素、插入元素、創(chuàng)建文本元素的 API 包裝成一個個函數(shù),然后作為參數(shù)傳遞給創(chuàng)建渲染器的函數(shù)進行創(chuàng)建一個針對 DOM 平臺的渲染器。

我們平時一般都是這樣創(chuàng)建一個 Vue3 應(yīng)用的:const app = createApp(App),根據(jù)上面的代碼我們可以知道這個 createApp 函數(shù)是創(chuàng)建渲染器函數(shù) createRenderer 返回的對象中的 createApp 方法,而 createApp 方法又是通過 createAppAPI 函數(shù)創(chuàng)建的,接下來,我們來看看 createAppAPI 函數(shù)的具體實現(xiàn)。

// 創(chuàng)建 Vue3 應(yīng)用實例對象
function createAppAPI(render) {
    return function createApp(rootComponent) {
        // 創(chuàng)建 Vue3 應(yīng)用實例對象
        const app = {
            // 實例掛載方法
            mount(rootContainer) {
                // 創(chuàng)建根組件虛擬DOM
                const vnode = createVNode(rootComponent)
                // 把根組件的虛擬DOM 渲染到 #app 節(jié)點上
                render(vnode, rootContainer)
            }
        }
        return app
    }
}

我可以看到具體創(chuàng)建 Vue3 應(yīng)用實例對象的 createAppAPI 函數(shù)是一個閉包函數(shù),主要通過閉包進行緩存不同渲染器內(nèi)的 render 方法,接下來就是返回一個具體創(chuàng)建 Vue3 應(yīng)用實例對象的 createApp 方法, const app = createApp(App) 中的 createApp 方法就來自于此。createApp 方法主要返回一個對象,對象里面就包含創(chuàng)建 Vue3 實例對象之后進行掛載的 mount 方法,在 createApp 方法的參數(shù)中接收根組件對象,然后 mount 方法掛載的時候,創(chuàng)建根組件的虛擬DOM,再把根組件的虛擬DOM 通過渲染器中的 render 方法進行渲染到具體元素節(jié)點上,我們一般就是 id 為 app 的元素上。

而在 Vue Vapor 中我們則不再需要渲染器這個實例了,因為 Vue Vapor 不存在虛擬 DOM 了,但為了兼容 Vue3 的 API,我們的 Vue Vapor 的啟動方式也應(yīng)該跟 Vue3 項目一樣。

接下來我們?nèi)崿F(xiàn) Vue Vapor 的應(yīng)用初始化吧。

Vue Vapor 的應(yīng)用初始化

為了日后才方便將 Vue3 的項目升級為 Vue Vapor 的項目,所以在 Vue Vapor 中我們也需要通過這樣的方式 createApp(App).mount('#app') 調(diào)用。因為 Vue Vapor 不存在虛擬DOM 了,所以也不需要渲染器了,所以我們可以直接從上面的 createAppAPI 函數(shù)中返回的 createApp 函數(shù)開始。

function createApp(rootComponent) {
    // 創(chuàng)建 Vue Vapor 應(yīng)用實例對象
    const app = {
        // 實例掛載方法
        mount(rootContainer) {
            // 把根組件的掛載到 #app 節(jié)點上
            render(rootComponent, rootContainer)
        }
    }
    return app
}

這樣我們的調(diào)用方式則變成:

const root = document.getElementById('app')
- render(App, root)
+ const app = createApp(App)
+ app.mount(root)

同時我們?yōu)榱艘部梢?app.mount('#app') 的方式調(diào)用,我們可以獲取根元素的方法在 render 函數(shù)中進行兼容處理。首先我們創(chuàng)建一個獲取根元素的方法:

function normalizeContainer(container) {
  return typeof container === 'string'
    ? (document.querySelector(container))
    : container
}

接著我們修改 render 方法:

function render(comp, container) {
    const render = typeof comp === 'function' ? comp : comp.render
    const block = render()
-    insert(block, container)
+    insert(block, (container = normalizeContainer(container)))
}

這樣我們的 Vue Vapor 的應(yīng)用初始化調(diào)用方式就跟 Vue3 的一樣了:

const app = createApp(App)
app.mount('#app')

Vue Vapor 組件初始化流程

我們知道在 SolidJS 中所謂組件只是代碼的一種組織方式,在程序初始化后就不再存在了,因為它的更新不再依賴于組件。但在 Vue Vapor 中因為需要兼容原來 Vue3 的 API,所以還是必須存在組件這個概念。

首先我們需要創(chuàng)建一個組件實例對象,這個組件實例對象上保存著這個組件的一些狀態(tài)信息,比如:指令、安裝的組件、是否已經(jīng)掛載、生命周期鉤子函數(shù)等。

export const createComponentInstance = (
  component
) => {
  const instance = {
    block: null,
    container: null, // set on mount
    component
    // TODO: registory of provides, appContext, lifecycles, ...
  }
  return instance
}

在創(chuàng)建了組件實例之后,我們就需要去掛載這個組件實例,所以我們還需要創(chuàng)建一個掛載組件的函數(shù)。

function mountComponent(
  instance,
  container
) {
    instance.container = container
    const render = typeof instance.component === 'function' ? instance.component : instance.component.render
    const block = render()
    insert(block, instance.container)
}

我們把原來屬于 render 函數(shù)的功能放在了 mountComponent 中進行實現(xiàn)。同時我們需要對 render 函數(shù)進行修改:

function render(comp, container) {
-    const render = typeof comp === 'function' ? comp : comp.render
-    const block = render()
-    insert(block, (container = normalizeContainer(container)))
+    const instance = createComponentInstance(comp)
+    mountComponent(instance, (container = normalizeContainer(container)))
}

我們之前的測試組件只是一個函數(shù)組件,而在 Vue3 中我們一般使用的都是狀態(tài)組件,包括 script setup 方式的組件,編譯后也是一個狀態(tài)組件,從代碼組織結(jié)構(gòu)上看就是一個對象,例子如下:

const App = {
    setup() {
        const count = ref(0)
        return { count } 
    },
    render(_ctx) {
        // 生成創(chuàng)建 button 標(biāo)簽的函數(shù)
        const _tmpl$ = template('<button></button>')
        // 真正進行創(chuàng)建模板內(nèi)容的地方
        const el = _tmpl$()
        el.addEventListener('click', () => {
            _ctx.count.value++
        })
        effect(() => {
            el.textContent = _ctx.count.value
        })
        return el
    }
}

那么我們要實現(xiàn)上述狀態(tài)組件的渲染,先要執(zhí)行組件的 setup 方法,然后拿到執(zhí)行結(jié)果然后做為組件 render 函數(shù)的參數(shù),然后執(zhí)行組件的 render 函數(shù)得到渲染結(jié)果。要實現(xiàn)此功能我們只需要將 mountComponet 函數(shù)進行迭代即可。

mountComponent 函數(shù)功能迭代如下:

function mountComponent(
  instance,
  container
) {
  instance.container = container

  const { component } = instance
  // 判斷是狀態(tài)組件還是函數(shù)組件
  const setupFn =
      typeof component === 'function' ? component : component.setup
  // 獲取 setup 方法的執(zhí)行結(jié)果
  const state = setupFn && setupFn()
  // 執(zhí)行 render 函數(shù)獲取 DOM 結(jié)果
  const block = instance.block = component.setup ? component.render(state) : state
  // 掛載組件DOM元素到到父級元素上
  insert(block, instance.container)
  // 設(shè)置已經(jīng)掛載的標(biāo)記
  instance.isMounted = true
  // TODO: lifecycle hooks (mounted, ...)
  // const { m } = instance
  // m && invoke(m)
}

我們測試發(fā)現(xiàn)狀態(tài)組件也可以實現(xiàn)渲染了,渲染結(jié)果如下:

代碼組織結(jié)構(gòu)調(diào)整優(yōu)化

到目前為止我們所有的代碼包括測試代碼還不到一百行,我們就基本把 Vue Vapor 運行時的基本原理搞清楚了,因為不存在虛擬 DOM 我們整個運行時的架構(gòu)要比存在虛擬DOM 的運行時架構(gòu)要輕盈很多的,這也是為什么無虛擬DOM 性能比較好的原因之一,而且可以說是非常重要的原因。沒有了虛擬DOM,則不再需要各種 diff 算法對比了,從而節(jié)省了性能開銷。

為了后續(xù)更好的開發(fā),也為了更好地組織我們的代碼,我們現(xiàn)在對我們的程序代碼組織架構(gòu)進行設(shè)計和重構(gòu)。

首先我們在根目錄新建一個 runtime-vapor 目錄把屬于 Vue Vapor 運行時的代碼全部放到這里面來,我們暫時的目錄結(jié)構(gòu)如下:

├── runtime-vapor
│   ├── src
│   │   ├── index.js        // Vapor 運行時程序入口文件
|   |   ├── apiCreateApp.js // 存放 createApp API 
|   |   ├── render.js       // 渲染相關(guān)的
|   |   ├── component.js    // 組件相關(guān)的
|   |   ├── template.js     // 生成原生模板的

apiCreateApp.js 文件內(nèi)容如下:

import { render } from "./render"
export function createApp(rootComponent) {
    // 創(chuàng)建 Vue3 應(yīng)用實例對象
    const app = {
        // 實例掛載方法
        mount(rootContainer) {
            // 把根組件的掛載到 #app 節(jié)點上
            render(rootComponent, rootContainer)
        }
    }
    return app
}

render.js 文件內(nèi)容如下:

import { createComponentInstance } from './component'
export function render(comp, container) {
    const instance = createComponentInstance(comp)
    mountComponent(instance, (container = normalizeContainer(container)))
}

function normalizeContainer(container) {
  return typeof container === 'string'
    ? (document.querySelector(container))
    : container
}

function mountComponent(
  instance,
  container
) {
  instance.container = container

  const { component } = instance
  // 判斷是狀態(tài)組件還是函數(shù)組件
  const setupFn =
      typeof component === 'function' ? component : component.setup
  // 獲取 setup 方法的執(zhí)行結(jié)果
  const state = setupFn && setupFn()
  // 執(zhí)行 render 函數(shù)獲取 DOM 結(jié)果
  const block = instance.block = component.setup ? component.render(state) : state
  // 掛載組件DOM元素到到父級元素上
  insert(block, instance.container)
  // 設(shè)置已經(jīng)掛載的標(biāo)記
  instance.isMounted = true
  // TODO: lifecycle hooks (mounted, ...)
  // const { m } = instance
  // m && invoke(m)
}

function insert(block, parent, anchor = null) {
    parent.insertBefore(block, anchor)
}

component.js 文件內(nèi)容如下:

let uid = 0
export const createComponentInstance = (
  component
) => {
  const instance = {
    uid: uid++,
    block: null,
    container: null, // set on mount
    component,
    isMounted: false
    // TODO: registory of provides, appContext, lifecycles, ...
  }
  return instance
}

template.js 文件內(nèi)容如下:

export function template(html) {
    let node
    const create = () => {
        const t = document.createElement("template")
        t.innerHTML = html
        return t.content.firstChild
    }
    const fn = () => (node || (node = create())).cloneNode(true)
    return fn 
}

index.js 文件內(nèi)容如下:

export { ref, effect } from '@vue/reactivity'
export { render } from './render'
export { template } from './template'
export { createApp } from './apiCreateApp'

接著我們把原來的測試組件對象 App,放到根目錄 src/App.js 文件中,代碼如下:

import { ref, template, effect } from "../runtime-vapor/src"
const App = {
    setup() {
        const count = ref(0)
        return { count } 
    },
    render(_ctx) {
        // 生成創(chuàng)建 button 標(biāo)簽的函數(shù)
        const _tmpl$ = template('<button></button>')
        // 真正進行創(chuàng)建模板內(nèi)容的地方
        const el = _tmpl$()
        el.addEventListener('click', () => {
            _ctx.count.value++
        })
        effect(() => {
            el.textContent = _ctx.count.value
        })
        return el
    }
}

export default App

那么 src/main.js 則可以像傳統(tǒng)的啟動方方式的代碼了,代碼如下:

import { createApp } from '../runtime-vapor/src'
import App from './App'

const app = createApp(App)
app.mount('#app')

至此我們的代碼就重構(gòu)完成了,重構(gòu)后的代碼組織結(jié)構(gòu)變得更加清晰了,各個文件的職責(zé)甚至可以通過文件名稱來進行知曉。

重構(gòu)后的代碼組織結(jié)構(gòu)如下:

├── runtime-vapor
│   ├── src
│   │   ├── index.js        // Vapor 運行時程序入口文件
|   |   ├── apiCreateApp.js // 存放 createApp API 
|   |   ├── render.js       // 渲染相關(guān)的
|   |   ├── component.js    // 組件相關(guān)的
|   |   ├── template.js     // 生成原生模板的
├── src
│   ├── App.js    // 測試組件
│   └── main.js   // 應(yīng)用入口文件
├── index.html
└── package.json

總結(jié)

本文從 Vue3 的渲染器與虛擬 DOM 機制出發(fā),對比分析了 Vue Vapor 在應(yīng)用初始化上的演進思路。

Vue Vapor 摒棄了虛擬 DOM 和渲染器層,直接將組件編譯為原生 DOM 操作,因此 createApp 不再依賴 createRenderer,而是直接創(chuàng)建應(yīng)用實例并調(diào)用 render 完成掛載。通過引入組件實例對象(createComponentInstance)和掛載函數(shù)(mountComponent),Vue Vapor 在兼容 Vue3 組件 API(如 setuprender)的同時,大幅簡化了運行時代碼結(jié)構(gòu)。去除了 diff 算法和 patch 流程后,整體架構(gòu)更加輕盈,性能開銷顯著降低。代碼組織上,將運行時拆分為 apiCreateApp、rendercomponent、template 等獨立模塊,職責(zé)清晰,便于后續(xù)擴展和維護。

這種設(shè)計既保證了 Vue3 項目未來可平滑升級,也為無虛擬 DOM 的高性能渲染提供了堅實基礎(chǔ),是 Vue 技術(shù)棧面向編譯時優(yōu)化的重要探索方向。

到此這篇關(guān)于詳解Vue Vapor 的應(yīng)用初始化的文章就介紹到這了,更多相關(guān)Vue Vapor應(yīng)用初始化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vite使用報錯解決方法合集

    Vite使用報錯解決方法合集

    這篇文章主要給大家介紹了關(guān)于Vite使用報錯解決方法的相關(guān)資料,這篇文中通過圖文以及代碼將遇到的一些報錯介紹的非常詳細,對大家學(xué)習(xí)或者使用vite具有一定的借鑒價值,需要的朋友可以參考下
    2023-08-08
  • 淺談Vue入門需掌握的知識

    淺談Vue入門需掌握的知識

    這篇文章主要介紹了淺談Vue入門需掌握的知識,感興趣的同學(xué)參考下
    2021-04-04
  • Vue3視頻播放組件 vue3-video-play使用方式

    Vue3視頻播放組件 vue3-video-play使用方式

    vue3-video-play是Vue3的視頻播放組件,基于原生video標(biāo)簽開發(fā),支持MP4和HLS流,提供全局/局部引入方式,可監(jiān)聽播放、暫停等事件,并具備字幕、播放列表等高級功能,適合靈活配置需求
    2025-09-09
  • Vue使用zTree插件封裝樹組件操作示例

    Vue使用zTree插件封裝樹組件操作示例

    這篇文章主要介紹了Vue使用zTree插件封裝樹組件操作,結(jié)合實例形式分析了vue.js整合zTree插件實現(xiàn)樹組件與使用相關(guān)操作技巧,需要的朋友可以參考下
    2019-04-04
  • 詳解windows下vue-cli及webpack 構(gòu)建網(wǎng)站(二)導(dǎo)入bootstrap樣式

    詳解windows下vue-cli及webpack 構(gòu)建網(wǎng)站(二)導(dǎo)入bootstrap樣式

    這篇文章主要介紹了詳解windows下vue-cli及webpack 構(gòu)建網(wǎng)站(二)導(dǎo)入bootstrap樣式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • vue項目中swiper輪播active圖片實現(xiàn)居中并放大

    vue項目中swiper輪播active圖片實現(xiàn)居中并放大

    這篇文章主要介紹了vue項目中swiper輪播active圖片實現(xiàn)居中并放大方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Vue2響應(yīng)式系統(tǒng)之set和delete

    Vue2響應(yīng)式系統(tǒng)之set和delete

    這篇文章主要介紹了Vue2響應(yīng)式系統(tǒng)之set和delete,通過為對象收集依賴,將對象、數(shù)組的修改、刪除也變成響應(yīng)式的了,同時為用戶提供了和方法,下文詳細介紹需要的朋友可以參考一下
    2022-04-04
  • Vue3.0之引入Element-plus ui樣式的兩種方法

    Vue3.0之引入Element-plus ui樣式的兩種方法

    本文主要介紹了Vue3.0之引入Element-plus ui樣式的兩種方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Vue實現(xiàn)剪貼板復(fù)制功能

    Vue實現(xiàn)剪貼板復(fù)制功能

    這篇文章主要介紹了Vue實現(xiàn)剪貼板復(fù)制功能,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • postcss-pxtorem設(shè)置不轉(zhuǎn)換UI框架的CSS單位問題

    postcss-pxtorem設(shè)置不轉(zhuǎn)換UI框架的CSS單位問題

    這篇文章主要介紹了postcss-pxtorem設(shè)置不轉(zhuǎn)換UI框架的CSS單位問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07

最新評論

张北县| 于都县| 峨山| 炎陵县| 子长县| 邢台县| 顺义区| 启东市| 阿巴嘎旗| 龙井市| 莱州市| 安徽省| 平顺县| 贡山| 永善县| 比如县| 四会市| 定远县| 沽源县| 阿坝县| 广德县| 安多县| 华安县| 龙陵县| 崇明县| 民丰县| 烟台市| 镇坪县| 通城县| 布尔津县| 科技| 广东省| 成安县| 太湖县| 达州市| 繁昌县| 玉林市| 吉木乃县| 阿拉善右旗| 聊城市| 隆昌县|