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

vue?parseHTML?函數源碼解析AST基本形成

 更新時間:2022年07月13日 17:20:18   作者:李李  
這篇文章主要為大家介紹了vue?parseHTML?函數源碼解析AST基本形成,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

AST(抽象語法樹)?

vue parseHTML函數解析器遇到結束標簽

在上篇文章中我們已經把整個詞法分析的解析過程分析完畢了。

例如有html(template)字符串:

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

產出如下:

{
attrs: [" id="app"", "id", "=", "app", undefined, undefined]
end: 14
start: 0
tagName: "div"
unarySlash: ""
}
{
attrs: []
end: 21
start: 18
tagName: "p"
unarySlash: ""
}

看到這不禁就有疑問? 這難道就是AST(抽象語法樹)??

非常明確的告訴你答案:No 這不是我們想要的AST,parse 階段最終生成的這棵樹應該是與如上html(template)字符串的結構一一對應的:

├── div
│   ├── p
│   │   ├── 文本

如果每一個節(jié)點我們都用一個 javascript 對象來表示的話,那么 div 標簽可以表示為如下對象:

{
  type: 1,
  tag: "div"
}

子節(jié)點

由于每個節(jié)點都存在一個父節(jié)點和若干子節(jié)點,所以我們?yōu)槿缟蠈ο筇砑觾蓚€屬性:parent 和 children ,分別用來表示當前節(jié)點的父節(jié)點和它所包含的子節(jié)點:

{
  type: 1,
  tag:"div",
  parent: null,
  children: []
}

同時每個元素節(jié)點還可能包含很多屬性 (attributes),所以我們可以為每個節(jié)點添加attrsList屬性,用來存儲當前節(jié)點所擁有的屬性:

{
  type: 1,
  tag:"div",
  parent: null,
  children: [],
  attrsList: []
}

按照以上思路去描述之前定義的 html 字符串,那么這棵抽象語法樹應該長成如下這個樣子:

{
  type: 1,
  tag: "div",
  parent: null,
  attrsList: [],
  children: [{
      type: 1,
      tag: "p",
      parent: div,
      attrsList: [],
      children:[
         {
          type: 3,
          tag:"",
          parent: p,
          attrsList: [],
          text:"{{ message }}"
         }
       ]
  }],
}

實際上構建抽象語法樹的工作就是創(chuàng)建一個類似如上所示的一個能夠描述節(jié)點關系的對象樹,節(jié)點與節(jié)點之間通過 parent 和 children 建立聯(lián)系,每個節(jié)點的 type 屬性用來標識該節(jié)點的類別,比如 type 為 1 代表該節(jié)點為元素節(jié)點,type 為 3 代表該節(jié)點為文本節(jié)點。

這里可參考NodeType:https://www.w3school.com.cn/jsref/prop_node_nodetype.asp

回顧我們所學的 parseHTML 函數可以看出,他只是在生成 AST 中的一個重要環(huán)節(jié)并不是全部。 那在Vue中是如何把html(template)字符串編譯解析成AST的呢?

Vue中是如何把html(template)字符串編譯解析成AST

在源碼中:

function parse (html) {
  var root;
  parseHTML(html, {
   start: function (tag, attrs, unary) {
      // 省略...
    },
    end: function (){
      // 省略...
    }
  }) 
  return root
}

可以看到Vue在進行模板編譯詞法分析階段調用了parse函數,parse函數返回root,其中root 所代表的就是整個模板解析過后的 AST,這中間還有兩個非常重要的鉤子函數,之前我們沒有講到的,options.start 、options.end。

接下來重點就來看看他們做了什么。

解析html

假設解析的html字符串如下:

<div></div>

這是一個沒有任何子節(jié)點的div 標簽。如果要解析它,我們來簡單寫下代碼。

function parse (html) {
  var root;
  parseHTML(html, {
   start: function (tag, attrs, unary) {
      var element = {
        type: 1,
        tag: tag,
        parent: null,
        attrsList: attrs,
        children: []
      }
      if (!root) root = element
    },
    end: function (){
      // 省略...
    }
  }) 
  return root
}

如上: 在start 鉤子函數中首先定義了 element 變量,它就是元素節(jié)點的描述對象,接著判斷root 是否存在,如果不存在則直接將 element 賦值給 root 。當解析這段 html 字符串時首先會遇到 div 元素的開始標簽,此時 start 鉤子函數將被調用,最終 root 變量將被設置為:

{
  type: 1,
  tag:"div",
  parent: null,
  children: [],
  attrsList: []
}

html 字符串復雜度升級: 比之前的 div 標簽多了一個子節(jié)點,span 標簽。

<div>
  <span></span>
</div>

代碼重新改造

此時需要把代碼重新改造。

function parse (html) {
  var root;
  var currentParent;
  parseHTML(html, {
   start: function (tag, attrs, unary) {
      var element = {
        type: 1,
        tag: tag,
        parent: null,
        attrsList: attrs,
        children: []
      }
      if (!root){
        root = element;
       }else if(currentParent){
        currentParent.children.push(element)
      }
      if (!unary) currentParent = element
    },
    end: function (){
      // 省略...
    }
  }) 
  return root
}

我們知道當解析如上 html 字符串時首先會遇到 div 元素的開始標簽,此時 start 鉤子函數被調用,root變量被設置為:

{
  type: 1,
  tag:"div",
  parent: null,
  children: [],
  attrsList: []
}

還沒完可以看到在 start 鉤子函數的末尾有一個 if 條件語句,當一個元素為非一元標簽時,會設置 currentParent 為該元素的描述對象,所以此時currentParent也是:

{
  type: 1,
  tag:"div",
  parent: null,
  children: [],
  attrsList: []
}

接著解析 html (template)字符串

接著解析 html (template)字符串,會遇到 span 元素的開始標簽,此時root已經存在,currentParent 也存在,所以會將 span 元素的描述對象添加到 currentParent 的 children 數組中作為子節(jié)點,所以最終生成的 root 描述對象為:

{
  type: 1,
  tag:"div",
  parent: null,
  attrsList: []
  children: [{
     type: 1,
     tag:"span",
     parent: div,
     attrsList: [],
     children:[]
  }], 
}

到目前為止好像沒有問題,但是當html(template)字符串復雜度在升級,問題就體現出來了。

<div>
 <span></span>
 <p></p>
</div>

在之前的基礎上 div 元素的子節(jié)點多了一個 p 標簽,到解析span標簽的邏輯都是一樣的,但是解析 p 標簽時候就有問題了。

注意這個代碼:

if (!unary) currentParent = element

在解析 p 元素的開始標簽時,由于 currentParent 變量引用的是 span 元素的描述對象,所以p 元素的描述對象將被添加到 span 元素描述對象的 children 數組中,被誤認為是 span 元素的子節(jié)點。而事實上 p 標簽是 div 元素的子節(jié)點,這就是問題所在。

為了解決這個問題,就需要我們額外設計一個回退的操作,這個回退的操作就在end鉤子函數里面實現。

解析div

這是一個什么思路呢?舉個例子在解析div 的開始標簽時:

stack = [{tag:"div"...}]

在解析span 的開始標簽時:

stack = [{tag:"div"...},{tag:"span"...}]

在解析span 的結束標簽時:

stack = [{tag:"div"...}]

在解析p 的開始標簽時:

stack = [{tag:"div"...},{tag:"p"...}]

在解析p 的標簽時:

這樣的一個回退操作看懂了嗎? 這就能保證在解析p開始標簽的時候,stack中存儲的是p標簽父級元素的描述對象。

接下來繼續(xù)改造我們的代碼。

function parse (html) {
  var root;
  var currentParent;
  var stack = [];  
  parseHTML(html, {
   start: function (tag, attrs, unary) {
      var element = {
        type: 1,
        tag: tag,
        parent: null,
        attrsList: attrs,
        children: []
      }
      if (!root){
        root = element;
       }else if(currentParent){
        currentParent.children.push(element)
      }
      if (!unary){
          currentParent = element;
          stack.push(currentParent);
       } 
    },
    end: function (){
      stack.pop();
      currentParent = stack[stack.length - 1]
    }
  }) 
  return root
}

通過上述代碼,每當遇到一個非一元標簽的結束標簽時,都會回退 currentParent 變量的值為之前的值,這樣我們就修正了當前正在解析的元素的父級元素。

以上就是根據 parseHTML 函數生成 AST 的基本方式,但實際上還不完美在Vue中還會去處理一元標簽,文本節(jié)點和注釋節(jié)點等等。

接下來你是否迫不及待要進入到源碼部分去看看了? 但Vue這塊代碼稍微復雜點,我們還需要有一些前期的預備知識。

parseHTML 函數源碼解析 AST 預備知識

以上就是vue parseHTML 函數源碼解析AST基本形成的詳細內容,更多關于vue parseHTML 函數AST的資料請關注腳本之家其它相關文章!

相關文章

  • 基于Vue2實現移動端圖片上傳、壓縮、拖拽排序、拖拽刪除功能

    基于Vue2實現移動端圖片上傳、壓縮、拖拽排序、拖拽刪除功能

    這篇文章主要介紹了基于Vue2實現移動端圖片上傳、壓縮、拖拽排序、拖拽刪除功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • 關于Vue不能監(jiān)聽(watch)數組變化的解決方法

    關于Vue不能監(jiān)聽(watch)數組變化的解決方法

    本文主要介紹了Vue不能監(jiān)聽(watch)數組變化的解決方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Vue使用emit傳參,父組件接收不到數據的問題及解決

    Vue使用emit傳參,父組件接收不到數據的問題及解決

    這篇文章主要介紹了Vue使用emit傳參,父組件接收不到數據的問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • vue下載excel的實現代碼后臺用post方法

    vue下載excel的實現代碼后臺用post方法

    這篇文章主要介紹了vue下載excel的實現代碼,后臺用post方法,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-05-05
  • vue項目中使用ts(typescript)入門教程

    vue項目中使用ts(typescript)入門教程

    最近項目需要將原vue項目結合ts的使用進行改造,本文從安裝到vue組件編寫進行了說明,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Vue波紋按鈕組件制作

    Vue波紋按鈕組件制作

    本文給大家分享了VUE制作點擊按鈕出現水波紋效果的組件過程,對此有需求的朋友可以跟著學習下。
    2018-04-04
  • vue+webpack實現異步組件加載的方法

    vue+webpack實現異步組件加載的方法

    下面小編就為大家分享一篇vue+webpack實現異步組件加載的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • vue3中使用Apache?ECharts的詳細方法

    vue3中使用Apache?ECharts的詳細方法

    最近在做一些數據透析的項目需要用到報表圖,那么報表圖好用的有老牌的ECharts,比較新意的AntV,思前馬后的想了一下還是用了Echarts,這篇文章主要介紹了vue3中使用Apache?ECharts,需要的朋友可以參考下
    2022-11-11
  • VUE表格顯示錯位的兩種解決思路分享

    VUE表格顯示錯位的兩種解決思路分享

    這篇文章主要介紹了VUE表格顯示錯位的兩種解決思路,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue2(三)實現子菜單展開收縮,帶動畫效果實現方法

    Vue2(三)實現子菜單展開收縮,帶動畫效果實現方法

    這篇文章主要介紹了vue實現收縮展開效果的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04

最新評論

南城县| 个旧市| 潞城市| 民勤县| 彩票| 仪征市| 尼勒克县| 民乐县| 湟源县| 清徐县| 四会市| 马边| 涿鹿县| 北海市| 涞水县| 禹城市| 浦北县| 龙江县| 和龙市| 台州市| 白城市| 嵩明县| 乐亭县| 白银市| 工布江达县| 孙吴县| 灌南县| 牙克石市| 绥芬河市| 图们市| 桂东县| 勃利县| 兴安盟| 盐津县| 富阳市| 乌拉特后旗| 裕民县| 邵阳市| 徐水县| 芜湖县| 天峻县|