zoukankan      html  css  js  c++  java
  • Vue template 模板编译产物分析

    概述

    compile 编译可以分成 parse、optimize 与 generate 三个阶段,最终需要得到 render function。这部分内容不算 Vue.js 的响应式核心,只是用来编译的,笔者认为在精力有限的情况下不需要追究其全部的实现细节,能够把握如何解析的大致流程即可

    举例

    <div :class="c" class="demo" v-if="isShow">
        <span v-for="item in sz">{{item}}</span>
    </div>
    

    入口详见 src/compiler/index.js

    import { parse } from './parser/index'
    import { optimize } from './optimizer'
    import { generate } from './codegen/index'
    import { createCompilerCreator } from './create-compiler'
    
    export const createCompiler = createCompilerCreator(function baseCompile(
        template: string,
        options: CompilerOptions
    ): CompiledResult {
        const ast = parse(template.trim(), options)
        optimize(ast, options)
        const code = generate(ast, options)
        return {
            ast,
            render: code.render,
            staticRenderFns: code.staticRenderFns
        }
    })
    

    parse

    会用正则等方式解析 template 模板中的指令、class、style等数据,形成AST。

    关键函数 src/compiler/parse/index.js 的 parseHTML

    上述例子会被解析成以下AST

    {
        /* 标签属性的map,记录了标签上属性 */
        'attrsMap': {
            ':class': 'c',
            'class': 'demo',
            'v-if': 'isShow'
        },
        /* 解析得到的:class */
        'classBinding': 'c',
        /* 标签属性v-if */
        'if': 'isShow',
        /* v-if的条件 */
        'ifConditions': [
            'exp': 'isShow'
        ],
        /* 标签属性class */
        'staticClass': 'demo',
        /* 标签的tag */
        'tag': 'div',
        /* 子标签数组 */
        'children': [
            {
                'attrsMap': {
                    'v-for': "item in sz"
                },
                /* for循环的参数 */
                'alias': "item",
                /* for循环的对象 */
                'for': 'sz',
                /* for循环是否已经被处理的标记位 */
                'forProcessed': true,
                'tag': 'span',
                'children': [
                    {
                        /* 表达式,_s是一个转字符串的函数 */
                        'expression': '_s(item)',
                        'text': '{{item}}'
                    }
                ]
            }
        ]
    }
    

    optimize

    optimize 的主要作用是标记 static 静态节点,这是 Vue 在编译过程中的一处优化,后面当 update 更新界面时,会有一个 patch 的过程, diff 算法会直接跳过静态节点,从而减少了比较的过程,优化了 patch 的性能。

    src/compiler/optimizer.js 的 markStatic

    给上述的 AST 里插入静态标识

    {
        'attrsMap': {
            ':class': 'c',
            'class': 'demo',
            'v-if': 'isShow'
        },
        'classBinding': 'c',
        'if': 'isShow',
        'ifConditions': [
            'exp': 'isShow'
        ],
        'staticClass': 'demo',
        'tag': 'div',
        /* 静态标志 */
        'static': false,
        'children': [
            {
                'attrsMap': {
                    'v-for': "item in sz"
                },
                'static': false,
                'alias': "item",
                'for': 'sz',
                'forProcessed': true,
                'tag': 'span',
                'children': [
                    {
                        'expression': '_s(item)',
                        'text': '{{item}}',
                        'static': false
                    }
                ]
            }
        ]
    }
    

    generate

    generate 是将 AST 转化成 render funtion 字符串的过程,得到结果是 render 的字符串以及 staticRenderFns 字符串。

    在经历过 parse、optimize 与 generate 这三个阶段以后,组件中就会存在渲染 VNode 所需的 render function 了。

    关键函数 src/compiler/codegen/index.js 的 generate

    举例将上述的AST编译成render语句

    with(this){
        return (isShow) ? 
        _c(
            'div',
            {
                staticClass: "demo",
                class: c
            },
            _l(
                (sz),
                function(item){
                    return _c('span',[_v(_s(item))])
                }
            )
        )
        : _e()
    }
    

    其中 _c 是 createElement 的简写,_l 等参见 core/instance/render-helpers/index.js 的函数简写定义

  • 相关阅读:
    PHP 文件包含之文件路径截断(转)
    如何使用Linux通用后门(转zafe)
    利用sqlmap和burpsuite绕过csrf token进行SQL注入 (转)
    正则表达式30分钟入门教程<转载>
    php empty()和isset()的区别<转载>
    $_SERVER详细资料整理(转)
    [C语言(VC)] 打造自己的键盘记录器 (zaroty)
    metasploit(MSF)终端命令大全
    linux提权总结(外文)
    kettle菜鸟学习笔记1----相关准备知识
  • 原文地址:https://www.cnblogs.com/everlose/p/12564868.html
Copyright © 2011-2022 走看看