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

Vue createRenderer 自定義渲染器從入門到實(shí)戰(zhàn)

 更新時(shí)間:2026年01月11日 11:37:08   作者:如果你好  
本文主要介紹了Vue createRenderer 自定義渲染器從入門到實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

?? Vue 3它不僅能高效渲染瀏覽器 DOM,還能實(shí)現(xiàn)小程序、Native 等多端運(yùn)行。而支撐這一切的核心,就是 createRenderer 函數(shù)。它允許我們自定義渲染邏輯,擺脫 Vue 內(nèi)置 DOM 渲染的限制,打造適配任意平臺的渲染器

一、自定義 DOM 渲染器

示例重點(diǎn)實(shí)現(xiàn)支持事件綁定的 patchProp 方法,還會加入虛擬節(jié)點(diǎn)更新案例,直觀看到渲染器的更新流程。

完整可運(yùn)行代碼

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Vue 自定義渲染器入門示例</title>
  <!-- 引入 Vue 3 完整版,方便瀏覽器直接運(yùn)行 -->
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
  <!-- 渲染掛載容器 -->
  <div id="app"></div>

  <script>
    // 從 Vue 中解構(gòu)出 createRenderer 和 h 函數(shù)
    const { createRenderer, h } = Vue;

    // 1. 創(chuàng)建自定義渲染器:傳入平臺渲染配置對象
    const renderer = createRenderer({
      // 創(chuàng)建元素節(jié)點(diǎn):根據(jù)標(biāo)簽名創(chuàng)建 DOM 元素
      createElement(tag) {
        console.log(`[渲染步驟] 創(chuàng)建元素節(jié)點(diǎn):<${tag}>`);
        return document.createElement(tag);
      },

      // 更新元素屬性:核心改造!支持普通屬性 + 事件綁定(onXXX 格式)
      patchProp(el, key, prevValue, nextValue) {
        // 判斷是否是事件屬性(以 on 開頭,且第二個(gè)字母大寫,如 onClick、onInput)
        const isEvent = key.startsWith('on') && /^on[A-Z]/.test(key);
        
        if (isEvent) {
          // 提取事件名(去掉 on 前綴,轉(zhuǎn)為小寫,如 onClick -> click)
          const eventName = key.slice(2).toLowerCase();
          
          // 移除舊的事件監(jiān)聽(如果有舊值)
          if (prevValue) {
            el.removeEventListener(eventName, prevValue);
          }
          
          // 綁定新的事件監(jiān)聽(如果有新值)
          if (nextValue) {
            el.addEventListener(eventName, nextValue);
            console.log(`[渲染步驟] 綁定事件:${eventName},回調(diào)函數(shù)已掛載`);
          }
        } else {
          // 普通屬性:直接用 setAttribute 處理
          if (nextValue === undefined || nextValue === null) {
            el.removeAttribute(key);
            console.log(`[渲染步驟] 移除普通屬性:${key}`);
          } else {
            el.setAttribute(key, nextValue);
            console.log(`[渲染步驟] 更新普通屬性:${key} = ${nextValue}`);
          }
        }
      },

      // 插入元素:將子元素插入到父元素的指定位置
      insert(el, parent, anchor) {
        console.log(`[渲染步驟] 插入元素:將 <${el.tagName.toLowerCase()}> 插入到 <${parent.tagName.toLowerCase()}>`);
        parent.insertBefore(el, anchor || null);
      },

      // 移除元素:從父節(jié)點(diǎn)中移除當(dāng)前元素
      remove(el) {
        console.log(`[渲染步驟] 移除元素:<${el.tagName.toLowerCase()}>`);
        el.parentNode.removeChild(el);
      },

      // 創(chuàng)建文本節(jié)點(diǎn):創(chuàng)建 DOM 文本節(jié)點(diǎn)
      createText(text) {
        console.log(`[渲染步驟] 創(chuàng)建文本節(jié)點(diǎn):${text}`);
        return document.createTextNode(text);
      },

      // 更新文本節(jié)點(diǎn):修改文本節(jié)點(diǎn)的內(nèi)容
      setText(node, text) {
        console.log(`[渲染步驟] 更新文本節(jié)點(diǎn):${node.nodeValue} → ${text}`);
        node.nodeValue = text;
      }
    });

    // 2. 獲取掛載容器
    const app = document.getElementById('app');

    // 3. 初始虛擬節(jié)點(diǎn)(無事件)
    const vnode1 = h('div', { title: '初始節(jié)點(diǎn)' }, 'Hello initial vnode');

    // 4. 1秒后更新的虛擬節(jié)點(diǎn)(帶 onClick 事件)
    const vnode2 = h(
      'div',
      {
        onClick() {
          console.log('更新了!點(diǎn)擊事件觸發(fā)成功~');
        },
        title: '更新后節(jié)點(diǎn)(帶點(diǎn)擊事件)' // 同時(shí)更新普通屬性
      },
      'hello world'
    );

    // 5. 先渲染初始虛擬節(jié)點(diǎn)
    renderer.render(vnode1, app);

    // 6. 1秒后更新虛擬節(jié)點(diǎn),觸發(fā) patchProp 處理事件和屬性更新
    setTimeout(() => {
      console.log('==== 開始更新虛擬節(jié)點(diǎn) ====');
      renderer.render(vnode2, app);
    }, 1000);
  </script>
</body>
</html>

運(yùn)行效果

  1. 打開瀏覽器運(yùn)行該 HTML 文件,頁面先顯示 Hello initial vnode,鼠標(biāo)懸浮彈出「初始節(jié)點(diǎn)」提示;
  2. 1秒后,文本自動更新為 hello world,懸浮提示變?yōu)椤父潞蠊?jié)點(diǎn)(帶點(diǎn)擊事件)」;
  3. 點(diǎn)擊文本所在的 div,控制臺打印 更新了!點(diǎn)擊事件觸發(fā)成功~;
  4. 全程控制臺會清晰打印渲染、更新、事件綁定的日志,直觀看到自定義渲染器的完整執(zhí)行流程。

二、核心拆解:這段代碼到底在做什么?

我們逐部分拆解代碼,理解 createRenderer 的核心組成和工作邏輯,重點(diǎn)解析新增的虛擬節(jié)點(diǎn)更新案例。

1. 核心引入:createRenderer和h函數(shù)

const { createRenderer, h } = Vue;

這兩個(gè)函數(shù)是實(shí)現(xiàn)自定義渲染的關(guān)鍵,各自承擔(dān)核心職責(zé):

  • createRenderer:Vue 3 提供的渲染器工廠函數(shù),接收一套「平臺渲染接口」,返回一個(gè)具備完整渲染能力的自定義渲染器實(shí)例。這個(gè)實(shí)例擁有 createApprender 方法,和 Vue 默認(rèn)的 DOM 渲染器功能一致,只是渲染邏輯由我們自定義。
  • h 函數(shù):全稱 createVNode,核心作用是構(gòu)建虛擬 DOM 節(jié)點(diǎn)(VNode)。它接收標(biāo)簽名/組件、屬性對象、子節(jié)點(diǎn)/文本內(nèi)容,返回一個(gè)標(biāo)準(zhǔn)的 VNode 對象,作為渲染器的輸入數(shù)據(jù)。

2. 核心步驟:創(chuàng)建自定義渲染器(createRenderer)

const renderer = createRenderer({ /* 渲染配置對象 */ });

createRenderer 接收一個(gè)配置對象作為唯一參數(shù),這個(gè)對象必須實(shí)現(xiàn) 6 個(gè)核心方法,它們是渲染器與「目標(biāo)平臺」的交互橋梁,負(fù)責(zé)將 VNode 轉(zhuǎn)換為目標(biāo)平臺的真實(shí)節(jié)點(diǎn)(這里是瀏覽器 DOM)。

6 個(gè)核心渲染方法詳解(DOM 平臺)

方法名核心作用入?yún)⒄f明
createElement創(chuàng)建元素節(jié)點(diǎn)tag:標(biāo)簽名(如 'div'、'p'),返回創(chuàng)建好的 DOM 元素
patchProp更新元素屬性el:真實(shí) DOM 元素、key:屬性名、prevValue:舊屬性值、nextValue:新屬性值
insert插入元素el:要插入的 DOM 元素、parent:父 DOM 元素、anchor:插入?yún)⒖脊?jié)點(diǎn)(null 則插入末尾)
remove移除元素el:要移除的 DOM 元素
createText創(chuàng)建文本節(jié)點(diǎn)text:文本內(nèi)容,返回創(chuàng)建好的 DOM 文本節(jié)點(diǎn)
setText更新文本節(jié)點(diǎn)node:真實(shí) DOM 文本節(jié)點(diǎn)、text:新的文本內(nèi)容

關(guān)鍵亮點(diǎn):patchProp支持事件綁定

本次改造的核心是 patchProp 方法,它不僅能處理 title 這類普通屬性,還能識別 onClick 這類事件屬性,實(shí)現(xiàn) DOM 事件的綁定與移除:

  • 先判斷屬性是否為 onXXX 格式的事件;
  • 提取原生事件名(onClickclick);
  • 遵循「先清后綁」原則,避免重復(fù)綁定導(dǎo)致多次觸發(fā)。

3. 新增亮點(diǎn):虛擬節(jié)點(diǎn)更新案例(核心解析)

自定義渲染器如何處理 VNode 更新,這也是 Vue 響應(yīng)式更新的底層縮影:

// 2. 獲取掛載容器
const app = document.getElementById('app');

// 3. 初始虛擬節(jié)點(diǎn)(無事件)
const vnode1 = h('div', { title: '初始節(jié)點(diǎn)' }, 'Hello initial vnode');

// 4. 1秒后更新的虛擬節(jié)點(diǎn)(帶 onClick 事件)
const vnode2 = h(
  'div',
  {
    onClick() {
      console.log('更新了!點(diǎn)擊事件觸發(fā)成功~');
    },
    title: '更新后節(jié)點(diǎn)(帶點(diǎn)擊事件)' // 同時(shí)更新普通屬性
  },
  'hello world'
);

// 5. 先渲染初始虛擬節(jié)點(diǎn)
renderer.render(vnode1, app);

// 6. 1秒后更新虛擬節(jié)點(diǎn),觸發(fā) patchProp 處理事件和屬性更新
setTimeout(() => {
  console.log('==== 開始更新虛擬節(jié)點(diǎn) ====');
  renderer.render(vnode2, app);
}, 1000);

這段代碼的核心邏輯:

  1. 初始渲染:調(diào)用 renderer.render(vnode1, app),渲染器將 vnode1 轉(zhuǎn)換為真實(shí) DOM,插入到掛載容器中,完成首次渲染;
  2. 延遲更新:1 秒后調(diào)用 renderer.render(vnode2, app),渲染器會自動對比 vnode1vnode2 的差異(屬性、文本內(nèi)容);
  3. 差異更新
    • 對于 title 屬性:觸發(fā) patchProp 方法,將舊值「初始節(jié)點(diǎn)」更新為新值「更新后節(jié)點(diǎn)(帶點(diǎn)擊事件)」;
    • 對于 onClick 事件:觸發(fā) patchProp 方法,綁定新的點(diǎn)擊事件回調(diào);
    • 對于文本內(nèi)容:觸發(fā) setText 方法,將「Hello initial vnode」更新為「hello world」;
  4. 無全量重建:整個(gè)更新過程沒有刪除舊 DOM 再創(chuàng)建新 DOM,而是只更新有差異的部分,這也是 Vue 渲染高效的核心原因。

4. 掛載應(yīng)用的兩種方式

案例使用 renderer.render(vnode, container) 直接渲染 VNode,除此之外,也可以通過 renderer.createApp(component).mount(container) 掛載組件,兩種方式均有效:

  • 直接渲染 VNode:更靈活,適合手動控制渲染流程(如本次的延遲更新案例);
  • 通過 createApp 掛載:更貼近日常 Vue 開發(fā),適合組件化開發(fā)場景。

三、深入理解:自定義渲染器的工作流程

整個(gè)渲染與更新過程可以總結(jié)為 4 個(gè)核心步驟,形成一個(gè)完整的閉環(huán):

  1. 生成 VNode:通過 h 函數(shù)創(chuàng)建標(biāo)準(zhǔn) VNode,提供渲染的數(shù)據(jù)源;
  2. 首次渲染:渲染器調(diào)用 6 個(gè)核心方法,將 VNode 轉(zhuǎn)換為真實(shí)節(jié)點(diǎn),插入到掛載容器中;
  3. VNode 對比:更新時(shí),渲染器對比新舊 VNode,找出屬性、文本等差異;
  4. 差異更新:針對差異部分,調(diào)用對應(yīng)的 patchProp、setText 等方法,更新真實(shí)節(jié)點(diǎn),無需全量重建。

到此這篇關(guān)于Vue createRenderer 自定義渲染器從入門到實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Vue createRenderer 自定義渲染器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

靖远县| 翁牛特旗| 淅川县| 团风县| 诸城市| 大竹县| 沾益县| 惠州市| 从化市| 塔河县| 日土县| 措勤县| 名山县| 土默特左旗| 宾阳县| 广州市| 南宫市| 甘肃省| 县级市| 宜阳县| 安福县| 新丰县| 吴堡县| 右玉县| 焦作市| 东兰县| 东源县| 胶南市| 监利县| 方山县| 宣城市| 平原县| 克什克腾旗| 始兴县| 东安县| 台南市| 镇远县| 新营市| 云霄县| 临猗县| 尼玛县|