템플릿 편집이란 무엇인가요? 다음 기사에서는 Vue의 템플릿 컴파일에 대해 설명하고 템플릿 컴파일의 원칙에 대해 논의합니다. 도움이 되기를 바랍니다.
vue는 <p>{{name}}</p>
<p></p>
와 같이 상태와 DOM 간의 바인딩 관계를 선언적으로 설명할 수 있는 템플릿 구문을 제공합니다. <p>{{name}}</p>
<p></p>
。
模板编译指的是模板将编译成render函数的过程,渲染函数的作用是每次执行时,会根据最新状态生成新的vnode。
编译的过程是:模板作为输入 -> 模板编译 阶段->生成 渲染函数
解析器
:将模板解析为AST(Abstract Syntax Tree 抽象语法树)优化器
:遍历AST标记静态节点,因为静态节点不可变,不需要为打上标签的静态节点创建新的虚拟节点,直接克隆已有的虚拟节点。代码生成器
:使用AST生成渲染函数。将AST转换成代码字符串。将代码字符串放入渲染函数中,导出被外界使用。假设如下代码,有el
、template
、render
、$mount
//复杂案例 let vue = new Vue({ el: '#app', data() { return { a: 1, b: [1] } }, render(h) { return h('div', { id: 'hhh' }, 'hello') }, template: `<div id='hhh' style="aa:1;bb:2"><a>{{xxx}}{{ccc}}</a></div>` }).$mount('#app') console.log(vue) //脚手架创建的案例 let vue = new Vue({ render: h => h(App) }).$mount('#app')
1)渲染到哪个根节点上:判断有无el属性,有的话直接获取el根节点,没有的话调用$mount时去获取根节点
2)渲染哪个模板到根节点上去:是否调用render
函数传入了模板 render: h => h(App) -> <App></App>
解析器-将模板解析成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之间的层级关系?使用栈
在触发开始标签的钩子函数时,如果当前标签不是自闭合标签,就push
进stack
。
在触发结束标签的钩子函数时,就从栈中pop
입력으로서의 템플릿-> 템플릿 컴파일 단계->렌더링 기능 생성
인터뷰 질문
파서< /code>: 템플릿을 AST(추상 구문 트리)로 구문 분석합니다.</li><li><code>Optimizer
: AST를 탐색하여 정적 노드를 표시합니다. 정적 노드는 변경할 수 없고 그럴 필요가 없기 때문입니다. 새 가상 노드를 생성하고 기존 가상 노드를 직접 복제하려면 정적 노드에 레이블을 지정합니다. 코드 생성기
: AST를 사용하여 렌더링 기능을 생성합니다. AST를 코드 문자열로 변환합니다. 코드 문자열을 렌더링 함수에 넣고 외부 세계에서 사용할 수 있도록 내보냅니다. 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)) ] ) ] ) }
render
함수를 호출하고 템플릿을 전달할지 여부 render: h => ; h(App) -> <App></App>
🎜{{}}
🎜🎜🎜DOM 간의 계층 관계를 결정하는 방법은 무엇입니까? 스택 사용 🎜push
는 stack
을 입력합니다. pop
가 재생됩니다🎜🎜🎜🎜🎜3. AST🎜🎜🎜🎜정적 노드를 표시합니다. 하위 트리의 이점🎜🎜优化器的内部实现主要分两步用递归的方式将所有节点添加 static 属性,true表示是静态的,false表示不是静态的。
静态根节点也是静态节点
如果一个静态根节点的子节点只有一个文本节点或没有子节点,那么不会标记成静态根节点,即使他们是,因为优化成本大于收益
怎么判断是否静态节点?
在将模板字符串解析成AST的时候,会根据不同的文本类型设置一个 type
type | 说明 | 是否时静态节点 |
---|---|---|
1 | 元素节点 | 进行一些排除 |
2 | 带遍历的动态文本节点 | 不是 |
3 | 不带遍历的纯文本节点 | 是 |
代码生成器的作用:将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来生成字符串,最先生成根节点,然后在子节点字符串生成后,将其拼接在根节点的参数中,子节点的子节点拼接在子节点的参数中,一层层拼接。
위 내용은 Vue 학습에서 템플릿 컴파일 원칙에 대해 이야기합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!