類vue將template轉爲vnode的流程

  • 類vue將template轉vnode全流程,模板爲html

    <div id="abc"><p class="www">{{msg}}</p><p class="hhh"><span>{{msg1}}</span></p></div>
    • 核心函數parseStartTag(起始標籤處理函數,獲得tagName,匹配attrs獲得key,value)執行完畢後調用parseHTML函數中填寫的options.start,設置根元素,父級元素,並儲存當前element於stack數組中,方便結束標籤函數執行時的取出處理
    • 核心函數parseText(文本處理函數,獲得{{}}之中的內容msg)判斷條件是未能匹配<符號時,執行options.chars將當前元素如p的element設置children爲匹配到text的element
    • 核心函數parseEndTag(結束標籤處理函數)判斷最後一個元素是否與當前的閉合標籤tagname匹配,匹配的話執行options.end將以前stack數組中儲存的上一個標籤移動到前一個標籤的子類並在stack數組中刪除他
    • 核心函數advance,推動索引,將已經匹配過的標籤或屬性從模板中剔除
    • 全文主要以parse執行parseHTML,parse傳入兩個參數,template模板,options(start:判斷起始標籤,將獲得的elemnt格式化爲標準模式,end:判斷結束標籤,將父級向上一層滾動,chars將{{}}內容截取)
    • 起始標籤的匹配細節vue

      <div id="abc">
      • 1.判斷是否以<爲開始,第一個標籤必然是,那麼進入parseStartTag處理起始標籤內容,startTagOpen正則進行匹配獲得標籤名<div或div,記錄此標籤的起始位置0,tagName爲匹配獲得的[1]div
      • advance將index向前推動<div個數目而且刪除模板的<div以進行下一步正則匹配
      • 若此時匹配不到起始標籤的閉合符號「>」,且可以匹配到屬性如id=「abc」,那麼將index繼續向前推id=「abc」的長度,刪除模板中id屬性,循環操做直到匹配獲得起始標籤的閉合符號,index再推動>符號的長度,模板刪除>後,記錄此時爲起始標籤的結束位置
      • 此時咱們匹配獲得的元素還不夠規範,長這樣⏬,須要進行修改
      {tagName: "div", attrs: 0: [" id="abc"", "id", "=", "abc", undefined, undefined, index: 0, input: " id="abc"><p class="www">{{msg}}</p><p class="hhh"><span>{{msg1}}</span></p></div>", groups: undefined], start: 0, end: 14}
      • handleStartTag方法判斷是否爲單標籤,若不是即將格式化後的對象塞入數組stack中這裏面沒有start,end.只有{id:"abc"}和標籤名,將lastTag設置爲當前格式化完畢的標籤
      attrsMap:{id: "abc"}
      children:[]
      parent:undefined
      tag:"div"
      type:1
      • 最後進行parse的options.start處理,將第一個標籤設置爲CurrentParent,同時設爲根元素,這樣第一個標籤<div id="abc">就處理完畢
    • 子元素標籤的匹配node

      • 因爲模板還沒遍歷完畢,繼續執行parseHTML,此時模板git

        html = "<p class="www">{{msg}}</p><p class="hhh"><span>{{msg1}}</span></p></div>"
      • 匹配到p的起始標籤繼續執行新的一輪起始標籤的匹配,區別在於此時須要設置currentParent即上一次遍歷獲得的div標籤處理後的element的children數組屬性加入當前p標籤處理後的element,再將currentParent賦值爲當前element,而且stack中塞入element,方便之後取出
    • 文本匹配github

      • 此時模板爲以下,再也不匹配<起始標籤符號,
      html = "{{msg}}</p><p class="hhh"><span>{{msg1}}</span></p></div>"
      • 設置var text = (void 0), rest = (void 0), next = (void 0);除了防止被重寫外,還能夠減小字節。void 0代替undefined省3個字節。
      • html.substring(0, >標籤所在位置)截取獲得{{msg}}, html.slice(>標籤所在位置)截取獲得剩餘的模板,將索引向前推動{{msg}}長度,獲取剩餘模板
      • 此後執行parse的options.chars方法處理text,parseText處理文本塞入tokens數組中獲得tokens = ["_s(msg)"],currentParent的children加入type爲2標記爲文本標籤
      {type: 2, expression: "_s(msg)+_s(msg)", text: "{{msg}}"}
    • 閉合標籤匹配express

      • 匹配完畢將index推動</p>個長度,獲取剩餘模板,執行parseEndTag
      • parseEndTag經過stack找到最近一個元素的標籤,若是存在執行options.end方法處理,將stack最後一個元素進行pre元素處理TODO:
      • 處理完該閉合標籤後將stack長度減一併把currentParent指向最後一位,即閉合標籤的父級,由於此時最高級div標籤的elemnet的children已經完成了p標籤的導入segmentfault

        {attrs:[{…}]
        attrsList:[{…}]
        attrsMap:{id: "abc"}
        children:Array(1)0:{type: 1, tag: "p", attrsList: Array(1), attrsMap: {…}, parent: {…}, …}
        parent:undefined
        tag:"div"
        type:1}

        參考文獻:Vue源碼解析之Template轉化爲AST
        倉庫:https://github.com/eeeeeeeaso...數組

相關文章
相關標籤/搜索