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

Vue執(zhí)行流程及渲染示例解析

 更新時(shí)間:2023年06月30日 08:54:31   作者:Skywang  
這篇文章主要為大家介紹了Vue執(zhí)行流程及渲染解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

最近想對(duì)之前看過(guò)的vue一些較原理的一些東西進(jìn)行總結(jié),今天就談?wù)剉ue實(shí)例創(chuàng)建到渲染的一個(gè)流程概述。說(shuō)的不對(duì)希望可以補(bǔ)充評(píng)論。

相信絕大多數(shù)的前端小伙伴已記不清做了多少項(xiàng)目,寫了多少代碼了,每個(gè)人如同教科書般地寫著Vue代碼:

      // 入口文件中的常見代碼
      new Vue({
        el: '#app',
        router: router,
        render: h => h(App)
      })

大家是否有想過(guò)Vue內(nèi)部是如何運(yùn)轉(zhuǎn)的呢,做了哪些事情呢?怎么在界面中渲染處預(yù)期效果呢!接下來(lái)我們慢慢探究!

初始化

Vue的構(gòu)造函數(shù)

// Vue構(gòu)造函數(shù)
function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  // 執(zhí)行初始化邏輯
  this._init(options)
}

通過(guò)上面的函數(shù)可以看出當(dāng)我們執(zhí)行new Vue()的時(shí)候,只執(zhí)行了一個(gè)_init方法。_init會(huì)根據(jù)傳入的選項(xiàng)對(duì)vue進(jìn)行初始化。我們初始化data的時(shí)候,vue會(huì)通過(guò) Object.defineProperty 的方式將data的屬性定義到vue實(shí)例上。這也就解釋了為什么我們可以在vue中通過(guò)this.name進(jìn)行賦值,可以修改data中name屬性的值了。

為了能實(shí)現(xiàn)的響應(yīng)式動(dòng)態(tài)變化數(shù)據(jù),vue又做了處理,創(chuàng)建一個(gè)observer對(duì)象,該對(duì)象與data綁定,通過(guò) Object.defineProperty 將data中的所有的屬性轉(zhuǎn)換成getter/setter。當(dāng)data中的屬性在vue實(shí)例中被訪問(wèn)(會(huì)觸發(fā)getter),observer 對(duì)象就會(huì)把該屬性收集為watcher實(shí)例的依賴,之后當(dāng)data中的屬性在vue實(shí)例中被改變(會(huì)觸發(fā)setter), observer 會(huì)通知依賴該屬性的 watcher 實(shí)例重新渲染頁(yè)面。

vue官網(wǎng)上的一張示意圖幫助大家再理解下這個(gè)處理過(guò)程:

上面我們分析了vue是如和做到數(shù)據(jù)更新的,接下來(lái)我們看看他是如何做到渲染界面的。首先,vue會(huì)把將我們編寫的HTML模板解析成一個(gè)AST描述對(duì)象,該對(duì)象是通過(guò)children和parent鏈接而成的樹形結(jié)構(gòu),完整地描述了HTML標(biāo)簽的所有信息。

HTML模板

      <div id="app">
          <p>{{msg}}</p>
      </div>

最終會(huì)解析成下面這種AST對(duì)象

{
   attrs: [{name: "id", value: ""app"", dynamic: undefined, start: 5, end: 13}],
   attrsList: [{name: "id", value: "app", start: 5, end: 13}],
   attrsMap: {id: "app"},
   children: [{
        attrsList: [],
        attrsMap: {},
        children: [],
        end: 33,
        parent: {type: 1, tag: "div", ...},
        plain: true,
        pre: undefined,
        rawAttrsMap:{},
        start: 19
        tag: "p",
        type: 1
   }],
   end: 263,
   parent: undefined,
   plain: false,
   rawAttrsMap:{id: {name: "id", value: "app", start: 5, end: 13}},
   start: 0
   tag: "div",
   type: 1
}

然后 vue 根據(jù)AST對(duì)象生成 render 函數(shù),該函數(shù)的函數(shù)體大致如下:

with(this){
    return _c('div', {attrs:{"id":"app"}}, [_c('p', [_v(_s(msg))])])
}

也就是說(shuō),我們的模板最終在vue內(nèi)部都是會(huì)以一個(gè)render函數(shù)的形式存在。

函數(shù) _c 是在初始化render環(huán)境的時(shí)候添加到vue實(shí)例上,用來(lái)創(chuàng)建 vnode 的全局實(shí)例方法。它可以通vue實(shí)例直接調(diào)用,主要是給vue內(nèi)部使用的vnode創(chuàng)建方法。
我們得到render函數(shù)之后,vue并未直接渲染成DOM樹,而是先通過(guò)render函數(shù)得到一個(gè)vnode。實(shí)際上這一步是非常有必要的,我們都知道頻繁大量地操作DOM節(jié)點(diǎn)是極耗性能的。vue在渲染之前通過(guò)對(duì)vnode的比較,可以大大規(guī)避非必要的DOM操作。下面是一個(gè)vnode大致結(jié)構(gòu):

{
    tag: "div", // 元素標(biāo)簽,如div
    children: [{tag: "p", ...}], // vnode 子節(jié)點(diǎn)數(shù)組
    data: {attrs: {id: "app"}}, // 數(shù)據(jù)對(duì)象例如,{attrs: {id: 'app'}}
    elm: DOM節(jié)點(diǎn)(div#app),// 所對(duì)應(yīng)的dom節(jié)點(diǎn)
    parent: undefined, // 父節(jié)點(diǎn)vnode
    context: Vue實(shí)例,  // 所對(duì)應(yīng)的vue實(shí)例
    ...
}

方法 _v 也是vue實(shí)例方法,內(nèi)部用以創(chuàng)建文本類型的vnode,在本例中,{{msg}}是一個(gè)文本節(jié)點(diǎn),所以需要使用 _v 來(lái)創(chuàng)建文本vnode。不過(guò)無(wú)論是文本類型的vnode還是非文本類型的vnode都是Vnode對(duì)象的實(shí)例。兩者的區(qū)別在于,文本類型的vnode不存在 tag 和 children。

// 創(chuàng)建一個(gè)文本類型的VNode
function createTextVNode (val) {
  return new VNode(undefined, undefined, undefined, String(val))
}

方法 _s 同樣也是vue的實(shí)例方法,內(nèi)部用來(lái)將接收的參數(shù)變成字符串返回,對(duì)于字符串和數(shù)值使用 Object.toString() 轉(zhuǎn)換,如果接收到的是一個(gè)對(duì)象,則使用 JSON.stringify()轉(zhuǎn)換。

function toString (val){
  return val == null
    ? ''
    : Array.isArray(val) || (isPlainObject(val) &amp;&amp; val.toString === Object.prototype.toString)
      ? JSON.stringify(val, null, 2)
      : String(val)
}

vnode 通過(guò) parent 和 children 連接父節(jié)點(diǎn)和子節(jié)點(diǎn),組成vnode樹。最后,vue根據(jù)diff之后的結(jié)果,執(zhí)行真正的dom節(jié)點(diǎn)的插入更新刪除等操作,同時(shí)觸發(fā)vue實(shí)例的生命周期鉤子函數(shù)。之后,vue要做的就是觀察數(shù)據(jù)的變化,進(jìn)而決定是否重新渲染頁(yè)面了。

繼續(xù)分析vue是如何進(jìn)行渲染的

創(chuàng)建DOM節(jié)點(diǎn)

有了vnode后,vue還需要根據(jù)vnode來(lái)創(chuàng)建DOM節(jié)點(diǎn)。如果是首次渲染,那么vue會(huì)走創(chuàng)建的邏輯。如果是數(shù)據(jù)的更新導(dǎo)致的重新渲染,那么vue會(huì)走更新的邏輯。

首次渲染

因?yàn)槭鞘状武秩?,所以不存在先前老的vnode,因此無(wú)需進(jìn)行比較。vue直接調(diào)用 createElm 方法創(chuàng)建DOM元素。具體的創(chuàng)建步驟如下:

1.首先為vnode創(chuàng)建DOM元素。

2.如果vnode有子節(jié)點(diǎn),逐個(gè)為其子節(jié)點(diǎn)創(chuàng)建DOM元素,并將子DOM元素插入到vnode的DOM元素上。

3.調(diào)用setAttribute 為vnode的DOM元素添加屬性。

4.將vnode的DOM元素插入到其父元素上。

重新渲染

如果不是首次渲染,而是由數(shù)據(jù)變化所觸發(fā)的重新渲染,那么vue會(huì)最大限度地復(fù)用已創(chuàng)建的DOM元素。而復(fù)用的前提就是通過(guò)比較新老vnode,找出需要更新的內(nèi)容,然后最小限度地進(jìn)行替換。這也是vue設(shè)計(jì)vnode的核心用途。vue源碼中可以看到(此處先忽略),當(dāng)新老vnode完全相等的情況下,vue不會(huì)對(duì)該節(jié)點(diǎn)重新渲染,直接跳過(guò)了。

如果新vnode發(fā)生了變化,那么vue會(huì)遵循以下步驟更新DOM元素:  

1.更新DOM元素的屬性。  

這個(gè)在首次渲染那部分提到了一些。vue內(nèi)實(shí)現(xiàn)了若干個(gè)屬性處理模塊,專門用于DOM元素屬性的創(chuàng)建和更新。這些模塊中基本都實(shí)現(xiàn)了create、update這兩個(gè)處理函數(shù)。create 負(fù)責(zé)DOM元素屬性的創(chuàng)建,update 負(fù)責(zé)DOM元素屬性的更新。cbs.update[i](oldVnode, vnode) 的意思就是逐個(gè)調(diào)用這些模塊上的 update 方法,以更新發(fā)生改變的DOM元素屬性。

2.更新DOM元素的子元素。關(guān)于DOM子元素的更新分為幾種情況

  • 如果新老vnode的子節(jié)點(diǎn)都是文本節(jié)點(diǎn)且文本內(nèi)容不同,處理方式更新DOM元素的textContent屬性值。
  • 如果新老vnode的子節(jié)點(diǎn)都是非文本節(jié)點(diǎn),需要調(diào)用 updateChildren 遞歸地去更新子節(jié)點(diǎn)。
  • 如果新vnode的子節(jié)點(diǎn)是非文本節(jié)點(diǎn),而老vnode的子節(jié)點(diǎn)是文本節(jié)點(diǎn),需要清除DOM元素的文本,并創(chuàng)建子vnode的DOM元素插入到其父節(jié)點(diǎn)的DOM元素上。
  • 如果新vnode的子節(jié)點(diǎn)不存在,但老vnode的子節(jié)點(diǎn)存在,那么調(diào)用 removeVnode 刪除老vnode的子節(jié)點(diǎn)對(duì)應(yīng)的DOM元素。
  • 如果老vnode的子節(jié)點(diǎn)是文本節(jié)點(diǎn),而新vnode的子節(jié)點(diǎn)不存在,則清空老DOM元素的文本。

大量的DOM操作會(huì)極損耗瀏覽器性能。vue在每次數(shù)據(jù)發(fā)生變化后,都會(huì)重新生成vnode節(jié)點(diǎn)。通過(guò)比較新老vnode節(jié)點(diǎn),找出需要進(jìn)行操作的最小DOM元素子集。根據(jù)變化點(diǎn),進(jìn)行DOM元素屬性、DOM子節(jié)點(diǎn)的更新。這種設(shè)計(jì)方式大大減少了DOM操作的次數(shù)

這次文章大部分都是看一些博客文章所了解的內(nèi)容,基本上可以了解vue如何創(chuàng)建和如何渲染界面,還是老話好記性不如爛筆頭 自己做了一些總結(jié) 可以加深理解!

更多關(guān)于Vue執(zhí)行流程及渲染解析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • ant design vue中表格指定格式渲染方式

    ant design vue中表格指定格式渲染方式

    這篇文章主要介紹了ant design vue中表格指定格式渲染方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • vue之Vue.use的使用場(chǎng)景及說(shuō)明

    vue之Vue.use的使用場(chǎng)景及說(shuō)明

    這篇文章主要介紹了vue之Vue.use的使用場(chǎng)景,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 利用Vue3和Plotly.js創(chuàng)建交互式表格

    利用Vue3和Plotly.js創(chuàng)建交互式表格

    在數(shù)據(jù)分析和可視化領(lǐng)域,經(jīng)常需要以表格的形式展示數(shù)據(jù),Plotly.js 是一款功能強(qiáng)大的 JavaScript 庫(kù),不僅可以創(chuàng)建交互式圖表,還可以動(dòng)態(tài)生成 HTML 表格,本文給大家介紹了如何用Vue3和Plotly.js創(chuàng)建交互式表格,需要的朋友可以參考下
    2024-07-07
  • Vue router傳遞參數(shù)并解決刷新頁(yè)面參數(shù)丟失問(wèn)題

    Vue router傳遞參數(shù)并解決刷新頁(yè)面參數(shù)丟失問(wèn)題

    這篇文章主要介紹了Vue router傳遞參數(shù)并解決刷新頁(yè)面參數(shù)丟失問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • elementUI table如何給表頭添加氣泡顯示

    elementUI table如何給表頭添加氣泡顯示

    這篇文章主要介紹了elementUI table如何給表頭添加氣泡顯示問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Vue3 核心特性Suspense 與 Teleport 原理解析

    Vue3 核心特性Suspense 與 Teleport 原理解析

    本文詳細(xì)解析了Vue3的核心特性Suspense和Teleport,包括它們的實(shí)現(xiàn)原理、核心源碼、生命周期流程、依賴追蹤機(jī)制等,通過(guò)深入理解這兩個(gè)API的設(shè)計(jì)哲學(xué),開發(fā)者可以提升代碼組織能力、優(yōu)化應(yīng)用性能和實(shí)現(xiàn)更優(yōu)雅的架構(gòu)設(shè)計(jì),感興趣的朋友一起看看吧
    2025-03-03
  • Vue局部組件數(shù)據(jù)共享Vue.observable()的使用

    Vue局部組件數(shù)據(jù)共享Vue.observable()的使用

    隨著組件的細(xì)化,就會(huì)遇到多組件狀態(tài)共享的情況,今天我們介紹的是 vue.js 2.6 新增加的 Observable API ,通過(guò)使用這個(gè) api 我們可以應(yīng)對(duì)一些簡(jiǎn)單的跨組件數(shù)據(jù)狀態(tài)共享的情況,感興趣的可以了解一下
    2021-06-06
  • vue計(jì)時(shí)器的實(shí)現(xiàn)方法

    vue計(jì)時(shí)器的實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了vue計(jì)時(shí)器的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Vue3項(xiàng)目搭建的詳細(xì)過(guò)程記錄

    Vue3項(xiàng)目搭建的詳細(xì)過(guò)程記錄

    使用VUE3開發(fā)很久了,但一直沒(méi)進(jìn)行總結(jié)和記錄,忙里偷閑整理搭建一套VUE3項(xiàng)目腳手架,下面這篇文章主要給大家介紹了關(guān)于Vue3項(xiàng)目搭建的詳細(xì)過(guò)程,需要的朋友可以參考下
    2022-10-10
  • Element el-checkbox-group v-model不支持對(duì)象(object)解決方案

    Element el-checkbox-group v-model不支持對(duì)象(object)解決方案

    本文主要介紹了Element el-checkbox-group v-model不支持對(duì)象(object)解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05

最新評(píng)論

辽宁省| 黄梅县| 松桃| 德清县| 永靖县| 东台市| 五指山市| 漯河市| 宁强县| 惠来县| 克拉玛依市| 吴川市| 岳阳县| 海晏县| 敦煌市| 永平县| 康乐县| 永平县| 岑巩县| 广汉市| 墨竹工卡县| 瓦房店市| 兴隆县| 太谷县| 兴隆县| 绥化市| 彩票| 尼玛县| 嘉禾县| 城市| 通渭县| 鹿泉市| 南充市| 凌云县| 海丰县| 垫江县| 合水县| 梁平县| 丰顺县| 武平县| 全椒县|