>웹 프론트엔드 >View.js >Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.

Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.

青灯夜游
青灯夜游앞으로
2023-03-07 19:01:001566검색

템플릿 편집이란 무엇인가요? 다음 기사에서는 Vue의 템플릿 컴파일에 대해 설명하고 템플릿 컴파일의 원칙에 대해 논의합니다. 도움이 되기를 바랍니다.

Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.

vue는 <p>{{name}}</p> <p></p>와 같이 상태와 DOM 간의 바인딩 관계를 선언적으로 설명할 수 있는 템플릿 구문을 제공합니다. <p>{{name}}</p> <p></p>

模板编译指的是模板将编译成render函数的过程,渲染函数的作用是每次执行时,会根据最新状态生成新的vnode

编译的过程是:模板作为输入 -> 模板编译 阶段->生成 渲染函数

面试题

  • vue的模板编译?
  • 模板编译Compiler中render讲解?
  • vue 模板编译的过程,每一个过程细说一下做了些什么
  • 模板编译,谁去解析AST树 【相关推荐:vuejs视频教程web前端开发

将模板编译成渲染函数

Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.

  • 解析器:将模板解析为AST(Abstract Syntax Tree 抽象语法树)
  • 优化器:遍历AST标记静态节点,因为静态节点不可变,不需要为打上标签的静态节点创建新的虚拟节点,直接克隆已有的虚拟节点。
  • 代码生成器:使用AST生成渲染函数。将AST转换成代码字符串。将代码字符串放入渲染函数中,导出被外界使用。

案例

Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.

1.模板确认

假设如下代码,有eltemplaterender$mount

//复杂案例
let vue = new Vue({
    el: &#39;#app&#39;,
    data() {
        return {
            a: 1,
            b: [1]
        }
    },
    render(h) {
        return h(&#39;div&#39;, { id: &#39;hhh&#39; }, &#39;hello&#39;)
    },
    template: `<div id=&#39;hhh&#39; style="aa:1;bb:2"><a>{{xxx}}{{ccc}}</a></div>`
}).$mount(&#39;#app&#39;)

console.log(vue)

//脚手架创建的案例
let vue = new Vue({
  render: h => h(App)
}).$mount(&#39;#app&#39;)

Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.

1)渲染到哪个根节点上:判断有无el属性,有的话直接获取el根节点,没有的话调用$mount时去获取根节点

2)渲染哪个模板到根节点上去:是否调用render 函数传入了模板 render: h => h(App) -> <app></app>

  • 有render:这时候优先执行render函数,render优先级 > template
  • 无render:
    • 有template:template解析成render函数的所需格式-代码字符串,并使用调用render函数渲染
    • 无template:el根节点的outerHTML解析成render函数的所需格式-代码字符串,并使用调用render函数渲染
      3.渲染的方式:无论什么情况,最后都统一是要使用render函数渲染

2.解析器-将模板解析成AST

解析器-将模板解析成AST

<div>
  <p>{{name}}</p>
</div>

将上述模板解析成AST后,AST抽象语法树就是使用JS中的对象来描述一个节点,一个对象表示一个节点。

{
  tag: "div"
  type: 1, //节点类型
  staticRoot: false,
  static: false,
  plain: true,
  parent: undefined, //存放父节点
  attrsList: [],
  attrsMap: {},
  children: [ //存放孩子节点
      {
      tag: "p"
      type: 1,
      staticRoot: false,
      static: false,
      plain: true,
      parent: {tag: "div", ...},
      attrsList: [],
      attrsMap: {},
      children: [{
          type: 2,
          text: "{{name}}",
          static: false,
          expression: "_s(name)"
      }]
    }
  ]
}

解析器的工作原理

解析器的原理的是一小段一小段地截取模板字符串,每截取一小段字符串,就会根据截取出来的字符串类型触发不同的钩子函数,直到模板字符串截空停止。然后使用栈来确定层级关系

解析器内部分也分几个子解析器,如HTML解析器、文本解析器等。

HTML解析器的作用是解析HTML,在解析HTML的过程中不断触发各种钩子函数,

  • 开始标签的钩子函数中可以构建元素类型的节点
  • 文本钩子函数中可以构建文本类型的节点
  • 注释钩子函数中可以构建注释类型的节点
  • 结束标签钩子函数

文本解析器是对HTML解析出来的文本进行二次加工,比如插值语法{{}}

如何确定DOM之间的层级关系?使用栈
在触发开始标签的钩子函数时,如果当前标签不是自闭合标签,就pushstack
在触发结束标签的钩子函数时,就从栈中pop

템플릿 컴파일은 템플릿을 렌더링 함수로 컴파일하는 과정을 의미합니다. 렌더링 함수의 기능은 실행될 때마다 최신 상태를 기반으로 새로운 vnode를 생성하는 것입니다. 컴파일 프로세스는 다음과 같습니다. 입력으로서의 템플릿-> 템플릿 컴파일 단계->렌더링 기능 생성

인터뷰 질문

🎜🎜🎜템플릿을 렌더링 함수로 컴파일🎜🎜🎜🎜
  • 파서: 템플릿을 AST(추상 구문 트리)로 구문 분석합니다.
  • Optimizer: AST를 탐색하여 정적 노드를 표시합니다. 정적 노드는 변경할 수 없고 그럴 필요가 없기 때문입니다. 새 가상 노드를 생성하고 기존 가상 노드를 직접 복제하려면 정적 노드에 레이블을 지정합니다.
  • 코드 생성기: AST를 사용하여 렌더링 기능을 생성합니다. AST를 코드 문자열로 변환합니다. 코드 문자열을 렌더링 함수에 넣고 외부 세계에서 사용할 수 있도록 내보냅니다.

🎜🎜Case🎜

🎜여기에 이미지 설명 삽입🎜🎜🎜🎜1. 템플릿 확인🎜🎜🎜 el을 사용하여 다음 코드를 가정합니다. 코드>, <code>템플릿, 렌더링, $mount🎜
<div>
  <p>{{name}}</p>
</div>
//生成的render渲染函数
{
  render: `with(this){return _c('div',[_c('p',[_v(_s(name))])])}`
}
//格式化后
with(this){
  return _c(
    'div',
    [
      _c(
        'p',
        [
          _v(_s(name))
        ]
      )
    ]
  )
}
🎜여기에 그림 설명 삽입🎜🎜🎜1) 렌더링할 루트 노드🎜: el 속성이 있는지 확인하고, 그렇다면 가져오기 el 직접 루트 노드, 그렇지 않은 경우 $mount🎜🎜🎜 호출 시 루트 노드를 가져옵니다. 2) 루트 노드에 렌더링할 템플릿🎜: render 함수를 호출하고 템플릿을 전달할지 여부 render: h =&gt ; h(App) -> <app></app>🎜
  • render 사용: 이때 렌더링 기능이 먼저 실행됩니다. 🎜렌더링 우선순위> 템플릿🎜
  • 렌더링 없음:
    • 템플릿 사용: 템플릿은 렌더링 함수의 필수 형식(코드 문자열)으로 구문 분석되고 이라는 렌더링 함수를 사용하여 렌더링됩니다. li>
    • 템플릿 없음: el 루트 노드의 externalHTML 렌더 함수에서 요구하는 형식(코드 문자열)으로 파싱하고 렌더 함수를 사용하여 렌더링
      3. 렌더링 방법: 상황에 관계없이 최종 단계는 렌더링 기능을 사용하여 render🎜
    • ul>
🎜
🎜🎜2. Parser - 템플릿을 AST🎜🎜🎜Parser로 구문 분석하는 것입니다. - 템플릿을 AST로 구문 분석🎜rrreee🎜위 템플릿을 구문 분석 AST 이후 AST 추상 구문 트리는 JS의 개체를 사용하여 노드를 설명하고 하나의 개체가 노드를 나타냅니다. 🎜rrreee

🎜🎜파서의 작동 원리🎜

🎜🎜파서의 원리는 템플릿 문자열을 작은 섹션으로 가로채는 것입니다. 문자열이 차단되면 템플릿 문자열이 잘려 중지될 때까지 차단된 문자열 유형에 따라 다양한 후크 기능이 트리거됩니다. 그런 다음 스택을 사용하여 계층적 관계를 결정합니다. 파서의 내부 부분도 HTML 파서, 텍스트 파서 등과 같은 여러 하위 파서로 나뉩니다. 🎜🎜🎜HTML 파서의 역할은 HTML을 파싱하는 것입니다🎜 HTML을 파싱하는 과정에서 다양한 Hook 기능이 지속적으로 발생합니다. 🎜
  • 시작 태그의 Hook 기능은 요소 유형의 노드를 구축할 수 있습니다. /li>텍스트 Hook 함수로 텍스트형 노드 생성 가능
  • Comment Hook 함수로 주석형 노드 생성 가능
  • 태그 Hook 함수 종료
🎜Text 파서는 HTML에서 파싱된 텍스트에 대해 2차 처리를 수행합니다. 예를 들어 보간 구문 {{}}🎜🎜🎜DOM 간의 계층 관계를 결정하는 방법은 무엇입니까? 스택 사용 🎜
시작 태그의 후크 기능을 실행할 때 현재 태그가 자체 닫힘 태그가 아닌 경우 pushstack을 입력합니다.
종료 태그의 후크 기능이 실행되면 스택에서 pop가 재생됩니다🎜🎜🎜🎜🎜3. AST🎜🎜🎜🎜정적 노드를 표시합니다. 하위 트리의 이점🎜🎜
  • 每次重新渲染时,不需要为静态子树创建新虚拟子树,克隆已存在的静态子树
  • 在虚拟DOM中打补丁(patching)的过程可以跳过 ,静态子树是不可变的

优化器的内部实现主要分两步用递归的方式将所有节点添加 static 属性,true表示是静态的,false表示不是静态的。

  • 在AST中找出所有静态节点并打上标记
    静态节点:DOM不会发生变化的节点
    通过递归的方式从上向下标记静态节点,如果一个节点被标记为静态节点,但它的子节点却被标记为动态节点,就说明该节点不是静态节点,可以将它改为动态节点。静态节点的特征是它的子节点也必须是静态的。

静态根节点也是静态节点

  • **在AST中找出所有静态根节点并打上标记 **
    静态根节点:子节点全是静态节点的节点
    使用递归从上向下寻找,在寻找的过程中遇见的第一个静态节点就为静态根节点,同时不继续往下找。

如果一个静态根节点的子节点只有一个文本节点或没有子节点,那么不会标记成静态根节点,即使他们是,因为优化成本大于收益

怎么判断是否静态节点?
在将模板字符串解析成AST的时候,会根据不同的文本类型设置一个 type

type 说明 是否时静态节点
1 元素节点 进行一些排除
2 带遍历的动态文本节点 不是
3 不带遍历的纯文本节点

4.代码生成器-将AST转化成渲染函数中的代码字符串

代码生成器的作用:将AST转化成渲染函数中的代码字符串

<div>
  <p>{{name}}</p>
</div>
//生成的render渲染函数
{
  render: `with(this){return _c('div',[_c('p',[_v(_s(name))])])}`
}
//格式化后
with(this){
  return _c(
    'div',
    [
      _c(
        'p',
        [
          _v(_s(name))
        ]
      )
    ]
  )
}

生成代码字符串是一个递归的过程,从顶向下依次处理每一个AST节点。
节点有三种类型,分别对应三种不同的创建方法与别名。

类型 创建方法 别名
元素节点 createElement _c
文本节点 createTextVNode _v
注释节点 createEmptyVNode _e

渲染函数可以生成VNode的原因:渲染函数其实是执行了createElement,而createElement可以创建VNode。

代码字符串的拼接过程

递归AST来生成字符串,最先生成根节点,然后在子节点字符串生成后,将其拼接在根节点的参数中,子节点的子节点拼接在子节点的参数中,一层层拼接。

(学习视频分享:vuejs入门教程编程基础视频

위 내용은 Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제