目錄
什么是AST
parse()
parseHTML()
parseStartTag()
handleStartTag()
首頁 web前端 js教程 什麼是AST? Vue源碼中AST語法樹的解析

什麼是AST? Vue源碼中AST語法樹的解析

Aug 02, 2018 am 11:43 AM
vue.js

这篇文章给大家介绍的内容是关于什么是AST?Vue源码中AST语法树的解析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

什么是AST

AST是指抽象语法树(abstract syntax tree),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式。Vue在mount过程中,template会被编译成AST语法树。
然后,经过generate(将AST语法树转化成render function字符串的过程)得到render函数,返回VNode。VNode是Vue的虚拟DOM节点,里面包含标签名、子节点、文本等信息,关于VNode的学习来自:https://blog.csdn.net/qq_3626...

<p>
    请输入:<input><br>
</p>
登入後複製

parse()

  var stack = [];
  var preserveWhitespace = options.preserveWhitespace !== false;
  var root;
  var currentParent;
  var inVPre = false;
  var inPre = false;
  var warned = false;

  function warnOnce (msg){
  }
  function closeElement (element){
  }
  //调用parseHTML,这里对options的内容省略
  parseHTML(template,options);
登入後複製

定义一些变量,root用于存放AST树根节点,currentParent存放当前父元素,stack用来辅助树建立的栈。接着调用parseHTML函数进行转化,传入template和options。
options的结构如下:

什麼是AST? Vue源碼中AST語法樹的解析

parseHTML()

parseHTML内容大纲

什麼是AST? Vue源碼中AST語法樹的解析

last = html;
    //确认html不是类似<script>,<style>这样的纯文本标签
    if (!lastTag || !isPlainTextElement(lastTag)) {
      var textEnd = html.indexOf(&#39;<&#39;);//判断html字符串是否以<开头
      if (textEnd === 0) {
        // 这里的Comment是Vue定义的正则表达式,判断html是不是<!-- -->注释
        //var comment = /^<!\--/;
        if (comment.test(html)) {
          var commentEnd = html.indexOf(&#39;-->&#39;);

          if (commentEnd >= 0) {
            if (options.shouldKeepComment) {
              options.comment(html.substring(4, commentEnd));
            }
            advance(commentEnd + 3);
            continue
          }
        }
        //判断是否处理向下兼容的注释,类似<![if !IE]>
        //var conditionalComment = /^<!\[/;
        if (conditionalComment.test(html)) {
          var conditionalEnd = html.indexOf(&#39;]>&#39;);

          if (conditionalEnd >= 0) {
            advance(conditionalEnd + 2);
            continue
          }
        }

        //获取<!DOCTYPE开头的标签内容
        // var doctype = /^<!DOCTYPE [^>]+>/i;
        var doctypeMatch = html.match(doctype);
        if (doctypeMatch) {
          advance(doctypeMatch[0].length);
          continue
        }

        //判断此段html是否结束标签
        // var endTag = new RegExp(("^<\\/" + qnameCapture + "[^>]*>"));
        // var qnameCapture = "((?:" + ncname + "\\:)?" + ncname + ")";
        // var ncname = &#39;[a-zA-Z_][\\w\\-\\.]*&#39;;
        var endTagMatch = html.match(endTag);
        if (endTagMatch) {
          var curIndex = index;
          advance(endTagMatch[0].length);
          parseEndTag(endTagMatch[1], curIndex, index);
          continue
        }

        // 匹配开始标签,获取match对象
        var startTagMatch = parseStartTag();
        if (startTagMatch) {
          handleStartTag(startTagMatch);
          if (shouldIgnoreFirstNewline(lastTag, html)) {
            advance(1);
          }
          continue
        }
        var text = (void 0), rest = (void 0), next = (void 0);
      if (textEnd >= 0) {
        rest = html.slice(textEnd);
        while (
          !endTag.test(rest) &&
          !startTagOpen.test(rest) &&
          !comment.test(rest) &&
          !conditionalComment.test(rest)
        ) {
            // 处理文本中的<字符
          next = rest.indexOf(&#39;<&#39;, 1);
          if (next < 0) { break }
          textEnd += next;
          rest = html.slice(textEnd);
        }
        text = html.substring(0, textEnd);
        advance(textEnd);
      }

      if (textEnd < 0) {
        text = html;
        html = &#39;&#39;;
      }

      if (options.chars && text) {
        options.chars(text);
      }
    } else {
      //代码省略
    }

    if (html === last) {
      //代码省略
    }
      }</script>
登入後複製

什麼是AST? Vue源碼中AST語法樹的解析

parseHTML使用while循环对传进来的html进行解析。首先获取var textEnd = html.indexOf('如果textEnd为0 说明是标签或者,再用正则匹配是否为注释标签,如果不是,再判断是否为向下兼容放入注释,如(详情见),如果不是,再判断是否已如果不是,再判断当前是否结束标签。var endTagMatch = html.match(endTag); 匹配不到那么就是开始标签,调用parseStartTag()函数解析。

parseStartTag()

  function parseStartTag () {
    var start = html.match(startTagOpen);
    if (start) {
      var match = {
        tagName: start[1],//标签名,本文的例子p
        attrs: [],
        start: index//0
      };//定义match对象
      advance(start[0].length);//index=4,html=" id="test">...
      var end, attr;
      //match对象的attrs
      //index=14
      while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
        advance(attr[0].length);
        match.attrs.push(attr);
      }
      // 在第二次while循环后 end匹配到结束标签 => ['>','']
      if (end) {
        match.unarySlash = end[1];
        advance(end[0].length);
        match.end = index;
        return match
      }
    }
  }
登入後複製

parseStartTag()构建一个match对象,对象里面包含标签名(tagName),标签属性(attrs),右开始标签的位置(end)。本文的例子,程序第一次进入该函数,所以tagName:p,start:0,end:14 match

 function advance (n) {
    index += n;
    html = html.substring(n);
  }
登入後複製

advance函数将局部变量index往后推 并切割字符串。

handleStartTag()

  function handleStartTag (match) {
    var tagName = match.tagName;
    var unarySlash = match.unarySlash;

    if (expectHTML) {
    //段落式元素
      if (lastTag === 'p' && isNonPhrasingTag(tagName)) {
        parseEndTag(lastTag);
      }
      // 可以省略闭合标签
      if (canBeLeftOpenTag$$1(tagName) && lastTag === tagName) {
        parseEndTag(tagName);
      }
    }

    var unary = isUnaryTag$$1(tagName) || !!unarySlash;

    var l = match.attrs.length;
    var attrs = new Array(l);
    //解析html属性值{name:'id',value:'test'}的格式
    for (var i = 0; i <p>在该函数中,对match进行了二次处理,根据标签名、属性生成一个新对象,push到最开始的stack数组中。<br>由于匹配的是起始标签,所以也会以这个标签名结束,此处的lastTag就是p。<br>函数最后调用了parse内部声明的方法start</p><pre class="brush:php;toolbar:false">function start (tag, attrs, unary) {
      //检查命名空间是否是svg或者math
      var ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag);

      // handle IE svg bug
      /* istanbul ignore if */
      if (isIE && ns === 'svg') {
        attrs = guardIESVGBug(attrs);
      }

      //创建element元素,element其实就是{type: 1,
      //tag: "p",
      //attrsList: [{name: "id", value: "test"}]],
      //attrsMap: makeAttrsMap(attrs), //parent:undefined
      //children: []}的一个对象
      var element = createASTElement(tag, attrs, currentParent);
      if (ns) {
        element.ns = ns;
      }
    
      //排除script,style标签
      if (isForbiddenTag(element) && !isServerRendering()) {
        element.forbidden = true;
        "development" !== 'production' && warn$2(
          'Templates should only be responsible for mapping the state to the ' +
          'UI. Avoid placing tags with side-effects in your templates, such as ' +
          "" + ', as they will not be parsed.'
        );
      }

      // apply pre-transforms
      for (var i = 0; i <p>对标签名进行校验,同时对属性进行更细致的处理,如v-pre,v-for,v-if等。最后调用processElement(element, options)对当前的树节点元素进行处理,具体如下:</p><pre class="brush:php;toolbar:false">  processKey(element);
  // 检测是否是空属性节点
  element.plain = !element.key && !element.attrsList.length;
 // 处理:ref或v-bind:ref属性
  processRef(element);
  //处理标签名为slot的情况
  processSlot(element);
  // 处理is或v-bind:is属性
  processComponent(element);
  for (var i = 0; i <p>start()生成element对象,再连接元素的parent和children节点,最后push到栈中,此时栈中第一个元素生成。结构如下:</p><p style="text-align: center;"><span class="img-wrap"><img src="/static/imghw/default1.png" data-src="https://img.php.cn//upload/image/187/717/423/1533181233204676.png" class="lazy" title="1533181233204676.png" alt="什麼是AST? Vue源碼中AST語法樹的解析"></span></p><p>接下来开始第二次循环,html变成了 请输入:<input type="text" v-model="message"></p><p>,因此这次解析的是文字:'请输入',具体代码分析在下一次~~~</p><p class="post-topheader custom- pt0">相关文章推荐:</p><p class="post-topheader custom- pt0"><a href="http://www.php.cn/php-weizijiaocheng-256904.html" target="_blank" class="title">使用PHP-Parser生成<span class="course-color">AST</span>抽象语法树</a></p>
登入後複製

以上是什麼是AST? Vue源碼中AST語法樹的解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

深入探討vite是怎麼解析.env檔的 深入探討vite是怎麼解析.env檔的 Jan 24, 2023 am 05:30 AM

使用vue框架開發前端專案時,我們部署的時候都會部署多套環境,往往開發、測試以及線上環境呼叫的介面網域都是不一樣的。如何能做到區分呢?那就是使用環境變數和模式。

圖文詳解如何在Vue專案中整合Ace程式碼編輯器 圖文詳解如何在Vue專案中整合Ace程式碼編輯器 Apr 24, 2023 am 10:52 AM

Ace 是一個用 JavaScript 寫的可嵌入程式碼編輯器。它與 Sublime、Vim 和 TextMate 等原生編輯器的功能和效能相符。它可以很容易地嵌入到任何網頁和 JavaScript 應用程式中。 Ace 被維護為Cloud9 IDE的主要編輯器 ,並且是 Mozilla Skywriter (Bespin) 專案的繼承者。

vue中組件化和模組化有什麼區別 vue中組件化和模組化有什麼區別 Dec 15, 2022 pm 12:54 PM

組件化和模組化的區別:模組化是從程式碼邏輯的角度進行劃分的;方便程式碼分層開發,確保每個每個功能模組的職能一致。元件化是從UI介面的角度進行規劃;前端的元件化,方便UI元件的重複使用。

探討如何在Vue3中撰寫單元測試 探討如何在Vue3中撰寫單元測試 Apr 25, 2023 pm 07:41 PM

在當今前端開發中,Vue.js 已經成為了一個非常流行的框架。隨著 Vue.js 的不斷發展,單元測試變得越來越重要。今天,我們將探討如何在 Vue.js 3 中編寫單元測試,並提供一些最佳實踐和常見的問題及解決方案。

深入聊聊vue3中的reactive() 深入聊聊vue3中的reactive() Jan 06, 2023 pm 09:21 PM

前言:在vue3的開發中,reactive是提供實現響應式資料的方法。日常開發這個是使用頻率很高的api。這篇文章筆者就來探索其內部運作機制。

Vue中JSX語法和模板語法的簡單比較(優劣勢分析) Vue中JSX語法和模板語法的簡單比較(優劣勢分析) Mar 23, 2023 pm 07:53 PM

在Vue.js中,開發人員可以使用兩種不同的語法來建立使用者介面:JSX語法和範本語法。這兩種文法各有優劣,以下就來探討它們的差異和優劣勢。

怎麼查詢目前vue的版本 怎麼查詢目前vue的版本 Dec 19, 2022 pm 04:55 PM

查詢目前vue版本的兩種方法:1、在cmd控制台內,執行「npm list vue」指令查詢版本,輸出結果就是vue的版本號資訊;2、在專案中找到並開啟package.json文件,查找「dependencies」項目即可看到vue的版本資訊。

淺析Vue3動態組件怎麼進行異常處理 淺析Vue3動態組件怎麼進行異常處理 Dec 02, 2022 pm 09:11 PM

Vue3動態元件怎麼進行異常處理?以下這篇文章帶大家聊聊Vue3 動態元件異常處理的方法,希望對大家有幫助!

See all articles