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

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

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

前言

在 SolidJS 中所謂組件只是代碼的一種組件方式,在程序初始化后就不再存在了,因?yàn)樗母虏辉僖蕾囉诮M件。但在 Vue Vapor 中因?yàn)樾枰嫒菰瓉?Vue3 的 API,所以還是必須存在組件這個(gè)概念。

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

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

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

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

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

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

渲染器的作用就是把虛擬DOM 渲染為真實(shí)DOM,所以渲染器需要把我們寫的那些元素進(jìn)行創(chuàng)建、刪除、修改和元素屬性的創(chuàng)建、刪除、修改。那么不同的平臺(tái),對(duì)元素操作的 API 都不一樣,所以在執(zhí)行 createRenderer 函數(shù)的時(shí)候,就需要根據(jù)不同平臺(tái)對(duì)元素操作特性 API 來創(chuàng)建渲染器。我們平時(shí)一般用到的都是 Vue3 默認(rèn)提供的 runtime-dom 這個(gè)包來創(chuàng)建的渲染器(renderer),runtime-dom 包就是根據(jù)瀏覽器的對(duì)元素操作的特有的DOM API 進(jìn)行創(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)建渲染器的時(shí)候是把操作原生 DOM 的創(chuàng)建元素、插入元素、創(chuàng)建文本元素的 API 包裝成一個(gè)個(gè)函數(shù),然后作為參數(shù)傳遞給創(chuàng)建渲染器的函數(shù)進(jìn)行創(chuàng)建一個(gè)針對(duì) DOM 平臺(tái)的渲染器。

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

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

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

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

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

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

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

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

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

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

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

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 中所謂組件只是代碼的一種組織方式,在程序初始化后就不再存在了,因?yàn)樗母虏辉僖蕾囉诮M件。但在 Vue Vapor 中因?yàn)樾枰嫒菰瓉?Vue3 的 API,所以還是必須存在組件這個(gè)概念。

首先我們需要?jiǎng)?chuàng)建一個(gè)組件實(shí)例對(duì)象,這個(gè)組件實(shí)例對(duì)象上保存著這個(gè)組件的一些狀態(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)建了組件實(shí)例之后,我們就需要去掛載這個(gè)組件實(shí)例,所以我們還需要?jiǎng)?chuàng)建一個(gè)掛載組件的函數(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 中進(jìn)行實(shí)現(xiàn)。同時(shí)我們需要對(duì) render 函數(shù)進(jìn)行修改:

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)))
}

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

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

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

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元素到到父級(jí)元素上
  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)組件也可以實(shí)現(xiàn)渲染了,渲染結(jié)果如下:

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

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

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

首先我們?cè)诟夸浶陆ㄒ粋€(gè) runtime-vapor 目錄把屬于 Vue Vapor 運(yùn)行時(shí)的代碼全部放到這里面來,我們暫時(shí)的目錄結(jié)構(gòu)如下:

├── runtime-vapor
│   ├── src
│   │   ├── index.js        // Vapor 運(yùn)行時(shí)程序入口文件
|   |   ├── 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)用實(shí)例對(duì)象
    const app = {
        // 實(shí)例掛載方法
        mount(rootContainer) {
            // 把根組件的掛載到 #app 節(jié)點(diǎn)上
            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元素到到父級(jí)元素上
  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'

接著我們把原來的測試組件對(duì)象 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>')
        // 真正進(jìn)行創(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)的啟動(dò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)變得更加清晰了,各個(gè)文件的職責(zé)甚至可以通過文件名稱來進(jìn)行知曉。

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

├── runtime-vapor
│   ├── src
│   │   ├── index.js        // Vapor 運(yùn)行時(shí)程序入口文件
|   |   ├── 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 機(jī)制出發(fā),對(duì)比分析了 Vue Vapor 在應(yīng)用初始化上的演進(jìn)思路。

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

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

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

相關(guān)文章

  • Vite使用報(bào)錯(cuò)解決方法合集

    Vite使用報(bào)錯(cuò)解決方法合集

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

    淺談Vue入門需掌握的知識(shí)

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

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

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

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

    這篇文章主要介紹了Vue使用zTree插件封裝樹組件操作,結(jié)合實(shí)例形式分析了vue.js整合zTree插件實(shí)現(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樣式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • vue項(xiàng)目中swiper輪播active圖片實(shí)現(xiàn)居中并放大

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

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

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

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

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

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

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

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

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

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

最新評(píng)論

新乡市| 麦盖提县| 乐亭县| 美姑县| 高碑店市| 兰考县| 汕尾市| 吉木乃县| 富蕴县| 奎屯市| 蓝田县| 和静县| 陕西省| 江油市| 武宁县| 平阴县| 封丘县| 涿州市| 云龙县| 三台县| 滁州市| 武邑县| 长寿区| 滨海县| 永登县| 河源市| 邢台县| 兴义市| 龙江县| 民勤县| 贵港市| 呼和浩特市| 靖边县| 开平市| 大同县| 南岸区| 大厂| 肥西县| 桑日县| 马鞍山市| 乐东|