.6-Vue源码之AST(2)

  上一节获取到了DOM树的字符串,准备进入compile阶段:

    // Line-9326
    function compileToFunctions(template,options,vm) {
        // 获取配置参数
        options = options || {};

        // ...

        // Go!
        var compiled = compile(template, options);

        // ...
    }

  该函数接受两个参数,DOM树字符串、配置参数,如图:,进函数:

    // Line-9287
    function compile(template, options) {
        var finalOptions = Object.create(baseOptions);
        var errors = [];
        var tips = [];
        finalOptions.warn = function(msg, tip$$1) {
            (tip$$1 ? tips : errors).push(msg);
        };
        // 合并参数
        if (options) {
            if (options.modules) {
                finalOptions.modules = (baseOptions.modules || []).concat(options.modules);
            }
            if (options.directives) {
                finalOptions.directives = extend(
                    Object.create(baseOptions.directives),
                    options.directives
                );
            }
            for (var key in options) {
                if (key !== ‘modules‘ && key !== ‘directives‘) {
                    finalOptions[key] = options[key];
                }
            }
        }
        // 核心编译函数
        var compiled = baseCompile(template, finalOptions);
        errors.push.apply(errors, detectErrors(compiled.ast));
        // 提示与报错属性添加
        compiled.errors = errors;
        compiled.tips = tips;
        return compiled
    }

  compile主要做了3件事:

  1、参数合并

  这里涉及到baseOptions与传进来的options,baseOptions是内置对象,与options合并后得到finalOptions作为参数传进第二步的函数。

    // Line-9529
    var baseOptions = {
        expectHTML: true,
        modules: modules$1,
        directives: directives$1,
        isPreTag: isPreTag,
        isUnaryTag: isUnaryTag,
        mustUseProp: mustUseProp,
        canBeLeftOpenTag: canBeLeftOpenTag,
        isReservedTag: isReservedTag,
        getTagNamespace: getTagNamespace,
        staticKeys: genStaticKeys(modules$1)
    };

  这个对象十分复杂,涉及的时候再做讲解。

  2、调用baseCompile函数

  该函数接受2个参数:字符串、参数对象。

    // Line-9261
    function baseCompile(template, options) {
        // 解析字符串为AST
        var ast = parse(template.trim(), options);
        // 优化
        optimize(ast, options);
        //
        var code = generate(ast, options);
        return {
            ast: ast,
            render: code.render,
            staticRenderFns: code.staticRenderFns
        }
    }

  简单看一眼这个函数,3个调用都很简单暴力,后面一个一个讲解。

  3、添加提示、报错属性并返回compiled值

  将过程中出现的error与tips作为属性添加到compiled对象上,以便一次性输出。

  跑流程的话,主要还是看第二步,理一理DOM树字符串是如何被解析和编译的,来看parse这个函数吧! 

  这函数太长了,分两部分来: 

    // Line-7982
    function parse(template, options) {
        // 参数修正
        warn$2 = options.warn || baseWarn;
        // 这几个属性都是原型链上面的
        platformGetTagNamespace = options.getTagNamespace || no;
        platformMustUseProp = options.mustUseProp || no;
        platformIsPreTag = options.isPreTag || no;
        preTransforms = pluckModuleFunction(options.modules, ‘preTransformNode‘);
        transforms = pluckModuleFunction(options.modules, ‘transformNode‘);
        postTransforms = pluckModuleFunction(options.modules, ‘postTransformNode‘);
        // 这是自家的 值为undefined…
        delimiters = options.delimiters;

        // 变量声明
        var stack = [];
        var preserveWhitespace = options.preserveWhitespace !== false;
        var root;
        var currentParent;
        var inVPre = false;
        var inPre = false;
        var warned = false;

        // 功能函数
        function warnOnce(msg) {
            if (!warned) {
                warned = true;
                warn$2(msg);
            }
        }

        function endPre(element) {
            if (element.pre) {
                inVPre = false;
            }
            if (platformIsPreTag(element.tag)) {
                inPre = false;
            }
        }

        parseHTML( /*...*/ );
        return root
    }

  首先是获取options参数的属性,其中大部分都是定义在原型上,即baseOptions,所以没什么讲的。唯一涉及的函数就是pluckModuleFunction,比较简单,看一下内容:

    // Line-5684
    function pluckModuleFunction(modules, key) {
        // 返回modules[key]组成的数组
        return modules ?
            modules.map(function(m) {
                return m[key];
            }).filter(function(_) {
                return _;
            }) : []
    }

  简而言之,就是返回一个数组,内容是modules[key],这里返回空数组。

  第一部分没什么讲的,主要是声明一些变量,第二部分才是核心:

    // Line-7982
    function parse(template, options) {
        // ...part-1

        parseHTML(template, {
            warn: warn$2,
            expectHTML: options.expectHTML,
            isUnaryTag: options.isUnaryTag,
            canBeLeftOpenTag: options.canBeLeftOpenTag,
            shouldDecodeNewlines: options.shouldDecodeNewlines,
            start: function start(tag, attrs, unary) {
                /* code... */
            },

            end: function end() {
                /* code... */
            },

            chars: function chars(text) {
                /* code... */
            }
        });
        return root
    }

  这部分就是一个函数的调用,第一个参数E为字符串,第二个参数是一个对象,包含多个属性与方法,属性内容如下:

    // Line-7578
    // 自闭合标签
    var isUnaryTag = makeMap(
        ‘area,base,br,col,embed,frame,hr,img,input,isindex,keygen,‘ +
        ‘link,meta,param,source,track,wbr‘
    );
    // 可以省略闭合标签
    var canBeLeftOpenTag = makeMap(
        ‘colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source‘
    );

    // 当前浏览器是否会对换行转义
    var shouldDecodeNewlines = inBrowser ? shouldDecode(‘\n‘, ‘
‘) : false;

    function shouldDecode(content, encoded) {
        var div = document.createElement(‘div‘);
        div.innerHTML = "<div a=\"" + content + "\">";
        return div.innerHTML.indexOf(encoded) > 0
    }

  第一个expectHTML在baseOptions中是默认true的,其余几个是标签名数组与换行转义判断的集合。

  剩余三个方法包括start、end、chars,单独讲不好讲,在parseHTML方法边跑边说。

  暂时结束,parseHTML方法非常长,单独讲。

时间: 2024-08-20 04:49:15

.6-Vue源码之AST(2)的相关文章

[Vue源码]一起来学Vue模板编译原理(一)-Template生成AST

本文我们一起通过学习Vue模板编译原理(一)-Template生成AST来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsunlei/javascrip

[Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串

本文我们一起通过学习Vue模板编译原理(二)-AST生成Render字符串来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsunlei/javascri

[Vue源码分析] v-model实现原理

最近小组有个关于vue源码分析的分享会,提前准备一下- 前言:我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化.那么v-model是怎么实现这一原理的呢?接下来探索一下这部分的源码. 前期准备①:vue2.5.2源码(用于阅读.查看关联等)②:建立vue demo,创建包含v-model指令的实例(用于debugger)以下为demo: genDirectives在模板的编译阶段, v-model跟其他指令一样,会被解析到 el.d

[Vue源码]一起来学Vue双向绑定原理-数据劫持和发布订阅

有一段时间没有更新技术博文了,因为这段时间埋下头来看Vue源码了.本文我们一起通过学习双向绑定原理来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsun

Vue源码(下篇)

上一篇是mount之前的添加一些方法,包括全局方法gloal-api,XXXMixin,initXXX,然后一切准备就绪,来到了mount阶段,这个阶段主要是 解析template 创建watcher并存入Dep 更新数据时更新视图 Vue源码里有两个mount 第一个 // src/platform/web/runtime/index.js Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean

Vue源码(上篇)

某课网有个488人名币的源码解读视频看不起,只能搜很多得资料慢慢理解,看源码能知道大佬的功能模块是怎么分块写的,怎么复用的,已经vue是怎么实现的 资料来自 vue源码 喜欢唱歌的小狮子 web喵喵喵 Vue.js源码全方位深入解析 恰恰虎的博客 learnVue 最后四集视频 总文件目录 scripts:包含构建相关的脚本和配置文件.作者声明一般开发不需要关注此目录 dist:构建出的不同分发版本,只有发布新版本时才会跟新,开发分支的新特性不会反映在此 packages:包含服务端渲染和模板编

vue源码解读预热-0

vueJS的源码解读 vue源码总共包含约一万行代码量(包括注释)特别感谢作者Evan You开放的源代码,访问地址为Github 代码整体介绍与函数介绍预览 代码模块分析 代码整体思路 总体的分析 从图片中可以看出的为采用IIFE(Immediately-Invoked Function Expression)立即执行的函数表达式的形式进行的代码的编写 常见的几种插件方式: (function(,){}(,))或(function(,){})(,)或!function(){}()等等,其中必有

Vue源码后记-钩子函数

vue源码的马拉松跑完了,可以放松一下写点小东西,其实源码讲20节都讲不完,跳了好多地方. 本人技术有限,无法跟大神一样,模拟vue手把手搭建一个MVVM框架,然后再分析原理,只能以门外汉的姿态简单过一下~ 想到什么写什么了,这节就简单说说钩子函数吧! vue中的钩子函数主要包含初始化的beforeCreated/created,Virtual Dom更新期间的beforeUpdate/updated,页面渲染期间的beforeMount/mounted,组件销毁期间的beforeDestroy

VUE源码解析心得

解读vue源码比较好奇的几个点: 1.生命周期是如何实现的 2.如何时间数据监听,实现双向绑定的 =======================华丽的分割线======================================================== 1. 官方图解如https://cn.vuejs.org/v2/guide/instance.html#生命周期图示,beforeCreate -> 观察数据变化 + 事件初始化  -> created -> el tem

大白话Vue源码系列(01):万事开头难

阅读目录 Vue 的源码目录结构 预备知识 先捡软的捏 Angular 是 Google 亲儿子,React 是 Facebook 小正太,那咱为啥偏偏选择了 Vue 下手,一句话,Vue 是咱见过的最对脾气的 MVVM 框架.之前也使用过 knockout,angular,react 这些框架,但都没有让咱产生 follow 的冲动.直到见到 Vue,简直是一见钟情啊. Vue 的官方文档已经对 Vue 如何使用提供了最好的教程,建议 Vue 新手直接去官网学习,而不要在网上找些质量参差不齐的