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

詳解Vue如何手寫(xiě)虛擬dom并進(jìn)行渲染

 更新時(shí)間:2024年03月11日 14:49:26   作者:不要止步于此  
這篇文章主要為大家詳細(xì)介紹了渲染器的工作原理,以及如何將真實(shí)dom或者組件用虛擬dom的形式進(jìn)行描述并渲染,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

虛擬dom如何渲染為真實(shí)dom

虛擬dom轉(zhuǎn)換為真實(shí)dom其實(shí)就是編寫(xiě)一個(gè)渲染函數(shù),將虛擬dom逐個(gè)創(chuàng)建為真實(shí)的dom元素并將對(duì)應(yīng)事件添加到當(dāng)前創(chuàng)建的元素上,再掛載到頁(yè)面的指定元素下。

認(rèn)識(shí)虛擬dom

虛擬dom其實(shí)就是用來(lái)描述真實(shí)dom的javascript對(duì)象。

來(lái)看下面例子,把一個(gè)真實(shí)dom用虛擬dom來(lái)進(jìn)行描述:

真實(shí)dom

<div onclick="onAlert()"><span>點(diǎn)擊我</span><span></span></div>
<script>
    function onAlert() {
      alert('點(diǎn)擊事件回調(diào)函數(shù)')
    }
</script>

轉(zhuǎn)換為虛擬dom

const vnode = {
  tag: 'div',
  props: {
    onClick: () => alert('點(diǎn)擊事件回調(diào)函數(shù)')
  },
  children: [
    {
      tag: 'span',
      children: '點(diǎn)擊我'
    },
    {
      tag: 'span',
    }
  ]
}

渲染器實(shí)現(xiàn)

/**
 * @param {object} vnode 虛擬dom對(duì)象
 * @param {HTMLElement} container 掛載虛擬dom的真實(shí)dom容器
 */
function renderer(vnode, container) {
  const { tag, props, children } = vnode
  const el = document.createElement(tag)
  for(const key in props) {
    if(/^on/.test(key)) {
      // 轉(zhuǎn)換為合法的監(jiān)聽(tīng)事件名稱
      const eventNmae = key.substring(2).toLowerCase()
      // 在當(dāng)前創(chuàng)建的el元素上掛載監(jiān)聽(tīng)事件
      el.addEventListener(eventNmae, props[key])
    }
  }

  if(typeof children === 'string') {
    // 創(chuàng)建一個(gè)文本節(jié)點(diǎn)添加到el元素下
    el.appendChild(document.createTextNode(children))
  } else if(Array.isArray(children)) {
    // 子節(jié)點(diǎn)為數(shù)組,遞歸調(diào)用renderer函數(shù)
    children.forEach(vnode => renderer(vnode, el))
  }
  console.log(container)
  // 將元素掛載到容器上
  container.appendChild(el)
}

現(xiàn)在將上面轉(zhuǎn)換的虛擬dom傳入函數(shù)執(zhí)行看下效果

// 把虛擬dom渲染到id為app的元素下
renderer(vnode, document.getElementById('app'))

下圖可看到虛擬dom已經(jīng)成功渲染為真實(shí)dom,并且點(diǎn)擊事件也成功觸發(fā)了!

虛擬dom描述組件

以上講了如何使用虛擬dom(vnode)描述真實(shí)dom,但還不夠!如果我們封裝了一個(gè)組件,又該如何使用虛擬dom進(jìn)行描述呢?

總的來(lái)說(shuō),組件就是一組dom元素的封裝,這組dom元素就是組件要渲染的內(nèi)容,比如前面例子的vnode對(duì)象就可以認(rèn)為是一個(gè)組件。

方法組件

const MyComponent = function () {
  return {
    tag: 'div',
    props: {
      onClick: () => alert('MyComponent點(diǎn)擊事件回調(diào)函數(shù)')
    },
    children: [
      {
        tag: 'span',
        children: 'MyComponent'
      },
      {
        tag: 'span',
      }
    ]
  }
}

對(duì)象組件

const MyComponent2 = {
  render() {
    return {
      tag: 'div',
      props: {
        onClick: () => alert('MyComponent2點(diǎn)擊事件回調(diào)函數(shù)')
      },
      children: [
        {
          tag: 'span',
          children: 'MyComponent2'
        },
        {
          tag: 'span',
        }
      ]
    }
  }
}

修改渲染器支持組件渲染

/**
 * @param {object} vnode 虛擬dom對(duì)象
 * @param {HTMLElement} container 掛載虛擬dom的真實(shí)dom容器
 */
function renderer(vnode, container) {
  const { tag } = vnode
  if(typeof tag === 'string') {
    mountElement(vnode, container)
  } else if(typeof tag === 'function') {
    mountComponent(tag(), container)
  } else if(typeof tag === 'object') {
    mountComponent(tag.render(), container)
  }
}

function mountElement(vnode, container) {
  const { tag, props, children } = vnode
  const el = document.createElement(tag)
  for(const key in props) {
    if(/^on/.test(key)) {
      // 轉(zhuǎn)換為合法的監(jiān)聽(tīng)事件名稱
      const eventNmae = key.substring(2).toLowerCase()
      // 在當(dāng)前創(chuàng)建的el元素上掛載監(jiān)聽(tīng)事件
      el.addEventListener(eventNmae, props[key])
    }
  }

  if(typeof children === 'string') {
    // 創(chuàng)建一個(gè)文本節(jié)點(diǎn)添加到el元素下
    el.appendChild(document.createTextNode(children))
  } else if(Array.isArray(children)) {
    // 子節(jié)點(diǎn)為數(shù)組,遞歸調(diào)用renderer函數(shù)
    children.forEach(vnode => renderer(vnode, el))
  }
  console.log(container)
  // 將元素掛載到容器上
  container.appendChild(el)
}

function mountComponent(vnode, container) {
  // 遞歸調(diào)用renderer
  renderer(vnode, container)
}

渲染組件

const vnode = {
  tag: 'div',
  children: [
    {
      tag: 'span',
      props: {
        onClick: () => alert('span點(diǎn)擊事件回調(diào)函數(shù)')
      },
      children: '我是span標(biāo)簽'
    },
    // 組件
    {
      tag: MyComponent,
    },
    // 組件
    {
      tag: MyComponent2,
    }
  ]
}

// 把虛擬dom渲染到id為app的元素下
renderer(vnode, document.getElementById('app'))

下圖可看到,對(duì)應(yīng)的組件及事件都已經(jīng)掛載成功!

總結(jié)

最后,是不是覺(jué)得渲染器其實(shí)也沒(méi)有想象中那么難!其實(shí)這只是一個(gè)創(chuàng)建節(jié)點(diǎn)的渲染器,但其精髓在于更新節(jié)點(diǎn)。假設(shè)我們對(duì)虛擬dom做了一些小修改,渲染器需要精確找到vnode對(duì)象的變更點(diǎn)且只更新變更的內(nèi)容,而不是重新走一遍創(chuàng)建節(jié)點(diǎn)的流程。

以上就是詳解Vue如何手寫(xiě)虛擬dom并進(jìn)行渲染的詳細(xì)內(nèi)容,更多關(guān)于Vue虛擬dom的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue中的$set的使用實(shí)例代碼

    Vue中的$set的使用實(shí)例代碼

    這篇文章主要介紹了Vue中的$set的使用,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-10-10
  • Vue自定義v-has指令,做按鈕權(quán)限判斷的步驟

    Vue自定義v-has指令,做按鈕權(quán)限判斷的步驟

    這篇文章主要介紹了Vue自定義v-has指令,做按鈕權(quán)限判斷的步驟,幫助大家更好的理解和學(xué)習(xí)使用vue框架,感興趣的朋友可以了解下
    2021-04-04
  • Vee-Validate的使用方法詳解

    Vee-Validate的使用方法詳解

    本篇文章主要介紹了Vee-Validate的使用方法詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • 詳解vue-video-player使用心得(兼容m3u8)

    詳解vue-video-player使用心得(兼容m3u8)

    這篇文章主要介紹了詳解vue-video-player使用心得(兼容m3u8),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • vue-cli開(kāi)發(fā)時(shí),關(guān)于ajax跨域的解決方法(推薦)

    vue-cli開(kāi)發(fā)時(shí),關(guān)于ajax跨域的解決方法(推薦)

    下面小編就為大家分享一篇vue-cli開(kāi)發(fā)時(shí),關(guān)于ajax跨域的解決方法(推薦),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • vue在取對(duì)象長(zhǎng)度length時(shí)候出現(xiàn)undefined的解決

    vue在取對(duì)象長(zhǎng)度length時(shí)候出現(xiàn)undefined的解決

    這篇文章主要介紹了vue在取對(duì)象長(zhǎng)度length時(shí)候出現(xiàn)undefined的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • vue如何獲取當(dāng)前url地址加端口號(hào)

    vue如何獲取當(dāng)前url地址加端口號(hào)

    這篇文章主要介紹了vue如何獲取當(dāng)前url地址加端口號(hào)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 函數(shù)式組件劫持替代json封裝element表格

    函數(shù)式組件劫持替代json封裝element表格

    這篇文章主要介紹了為大家函數(shù)式組件劫持替代json封裝element表格的過(guò)程思路及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 解決vue項(xiàng)目刷新后,導(dǎo)航菜單高亮顯示的位置不對(duì)問(wèn)題

    解決vue項(xiàng)目刷新后,導(dǎo)航菜單高亮顯示的位置不對(duì)問(wèn)題

    今天小編就為大家分享一篇解決vue項(xiàng)目刷新后,導(dǎo)航菜單高亮顯示的位置不對(duì)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • vue3生成隨機(jī)密碼的示例代碼

    vue3生成隨機(jī)密碼的示例代碼

    本文主要介紹了vue3生成隨機(jī)密碼的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評(píng)論

望奎县| 沙洋县| 城口县| 承德市| 合阳县| 岑巩县| 石河子市| 玛沁县| 邵阳县| 义乌市| 万盛区| 锦州市| 香格里拉县| 巴马| 天门市| 同仁县| 安徽省| 大兴区| 田阳县| 新晃| 岱山县| 攀枝花市| 图们市| 神木县| 云龙县| 藁城市| 金乡县| 偏关县| 海盐县| 福清市| 临高县| 垣曲县| 阿图什市| 双城市| 大渡口区| 旺苍县| 鹤庆县| 合山市| 广安市| 通辽市| 宁化县|