来源 刘涛

Vue的核心可以分为三个大块:数据处理和双向绑定、模板编译、虚拟dom。

前面我们对第一部分的主要内容双向绑定做了一个分析讲解,接下来我们说一说模板编译。

这一部分的内容比较多,也比较复杂。由于所涉及的情况太多了,我也不可能把每一种情况都覆盖到。

尽量做到既不啰嗦,又能分享更多的内容。前面我们也提到过,模板编译分为三个阶段:

生成ast、优化静态内容、生成render

官方文档中提到rendertemplate更加底层,许多人对render函数都不是很明白,

相信通过这一部分的分析,你可以对render基本做到了如指掌。

如果你在创建对象时直接传入render函数,模板编译这一步就可以直接跳过,这样效率肯定更高,

(react就是不用模板编译的, 如果vue比react效率高,那就是因为需要编译jsx?)

但同时我们编写代码的难度会增加很多。实际开发过程中,根据需要,恰当选择。

Vue对象上有一个全局函数compile,在src/entries/web-runtime-with-compiler.js中。

import { compileToFunctions } from 'web/compiler/index'
...
...
...
Vue.compile = compileToFunctions

该方法来自src/platforms/web/compiler/index文件。

import { isUnaryTag, canBeLeftOpenTag } from './util'
import { genStaticKeys } from 'shared/util'
import { createCompiler } from 'compiler/index' import modules from './modules/index'
import directives from './directives/index' import {
isPreTag,
mustUseProp,
isReservedTag,
getTagNamespace
} from '../util/index' export const baseOptions: CompilerOptions = {
expectHTML: true,
modules,
directives,
isPreTag,
isUnaryTag,
mustUseProp,
canBeLeftOpenTag,
isReservedTag,
getTagNamespace,
staticKeys: genStaticKeys(modules)
} const { compile, compileToFunctions } = createCompiler(baseOptions)
export { compile, compileToFunctions }

该文件中主要定义了一个baseOptions,它主要保存了解析模板时和平台相关的一些配置。

对应的src/platforms/weex/compiler/index中也有一份名称一样的配置。

这里我们简单说说web相关的这些配置都是什么意思。

  • expectHTML。目前具体还不是很明白,weex中没有改项,从字面意思来看,应该是是否期望HTML

  • modules。包括klassstyle,对模板中类和样式的解析。

  • directives。这里包括modelv-model)、htmlv-html)、text(v-text)三个指令。

  • isPreTag。是否是pre标签。

  • isUnaryTag。是否是单标签,比如imginputiframe等。

  • mustUseProp。需要使用props绑定的属性,比如valueselected等。

  • canBeLeftOpenTag。可以不闭合的标签,比如trtd等。

  • isReservedTag。是否是保留标签,html标签和SVG标签。

  • getTagNamespace。获取命名空间,svgmath

  • staticKeys。静态关键词,包括staticClass,staticStyle

上面这些方法或者属性,在编译模板时会用到。

这里知识简单的列出来它们的用途,方便看一眼。

我们来看createCompiler函数的实现。

export function createCompiler (baseOptions: CompilerOptions) {
const functionCompileCache: {
[key: string]: CompiledFunctionResult;
} = Object.create(null) // compile 函数的实现 // compileToFunctions 函数的实现 return {
compile,
compileToFunctions
}
}

该函数只是compilecompileToFunctions的简单封装,开始定义了functionCompileCache

它用来缓存编译之后的模板,方便之后复用。

因为compileToFunctions里面调用了compile,所以我们先看一下compile

  function compile (
template: string,
options?: CompilerOptions
): CompiledResult {
const finalOptions = Object.create(baseOptions)
const errors = []
const tips = []
finalOptions.warn = (msg, tip) => {
(tip ? tips : errors).push(msg)
} if (options) {
// merge custom modules
if (options.modules) {
finalOptions.modules = (baseOptions.modules || []).concat(options.modules)
}
// merge custom directives
if (options.directives) {
finalOptions.directives = extend(
Object.create(baseOptions.directives),
options.directives
)
}
// copy other options
for (const key in options) {
if (key !== 'modules' && key !== 'directives') {
finalOptions[key] = options[key]
}
}
} const compiled = baseCompile(template, finalOptions)
if (process.env.NODE_ENV !== 'production') {
errors.push.apply(errors, detectErrors(compiled.ast))
}
compiled.errors = errors
compiled.tips = tips
return compiled
}

我们从上往下,依次看看它都做了哪些事儿。

它接收两个参数templateoptionstemplate不用过多解释,

options在内部主要是用户自己定义的delimiters

finalOptions继承自我们上面提到的baseOptions

并添加了一个搜集错误的warn方法,然后合并了options传入的各种配置选项。

modulesdirectives合并方法不同是因为modules是数组,而directives是一个对象。

baseCompile中执行的就是模板编译的三个重要步骤,后面我们会详细讲解。

最终,返回编译之后的对象。

function compileToFunctions (
template: string,
options?: CompilerOptions,
vm?: Component
): CompiledFunctionResult {
options = options || {} ...
// check cache
const key = options.delimiters
? String(options.delimiters) + template
: template
if (functionCompileCache[key]) {
return functionCompileCache[key]
} // compile
const compiled = compile(template, options) // check compilation errors/tips
if (process.env.NODE_ENV !== 'production') {
if (compiled.errors && compiled.errors.length) {
warn(
`Error compiling template:\n\n${template}\n\n` +
compiled.errors.map(e => `- ${e}`).join('\n') + '\n',
vm
)
}
if (compiled.tips && compiled.tips.length) {
compiled.tips.forEach(msg => tip(msg, vm))
}
} // turn code into functions
const res = {}
const fnGenErrors = []
res.render = makeFunction(compiled.render, fnGenErrors)
const l = compiled.staticRenderFns.length
res.staticRenderFns = new Array(l)
for (let i = 0; i < l; i++) {
res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i], fnGenErrors)
} if (process.env.NODE_ENV !== 'production') {
if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
warn(
`Failed to generate render function:\n\n` +
fnGenErrors.map(({ err, code }) => `${err.toString()} in\n\n${code}\n`).join('\n'),
vm
)
}
}
return (functionCompileCache[key] = res)
}

compileToFunctions函数中,首先从缓存中获取编译结果,没有则调用compile函数来编译。

在开发环境,我们在这里会抛出编译过程中产生的错误,

最终返回一个含有render函数,和staticRenderFns数组的对象,并把它放在缓存中。

这里我们使用makeFunction来创建函数。

function makeFunction (code, errors) {
try {
return new Function(code)
} catch (err) {
errors.push({ err, code })
return noop
}
}

很简单,就是利用了我们new Function,并搜集了错误。

compilecompileToFunctions两个方法的不同之处有以下几点。

1、 compile返回的结果中render是字符串,staticRenderFns是字符串组成的数组,而compileToFunctions中把它们变成了函数。

2、 compile返回的结果中,有模板生成的ast和搜集到的错误。而compileToFunctions对其结果进行了一些处理。

vue-compile概述的更多相关文章

  1. 从零开始学 Web 之 Vue.js(一)Vue.js概述,基本结构,指令,事件修饰符,样式

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  2. vue的概述

    一.Vue的概述 Vue的开发模式 和 之前接触的jQuery.原生JSDOM操作是不同的,之前要想修改试图,首先找元素:在使用Vue时,专心把精力放在修改数据.DOM驱动 ---> 数据驱动. ...

  3. Vue.js - 概述

    概述 Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库.Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. Vue.js ...

  4. vue 传值 概述 个人理解

    1 父传子   子组件  props:[‘自定义属性名’]   父组件  v-bind:自定义属性名="值"  理解 子组件创建一个自定属性   父组件使用vue指令绑定到 自定义 ...

  5. 前端框架 Vue.js 概述

    Vue.js 是什么 图片 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视 ...

  6. 6. VUE 指令-概述

    指令 (Directives) 是带有 v- 前缀的特殊特性.指令特性的值预期是单个 JavaScript 表达式 (v-for是例外情况,稍后我们再讨论).指令的职责是,当表达式的值改变时,将其产生 ...

  7. vue.js组件化开发实践

    前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...

  8. 05-Vue入门系列之Vue实例详解与生命周期

    Vue的实例是Vue框架的入口,其实也就是前端的ViewModel,它包含了页面中的业务逻辑处理.数据模型等,当然它也有自己的一系列的生命周期的事件钩子,辅助我们进行对整个Vue实例生成.编译.挂着. ...

  9. Vue.2.0.5-Render 函数

    基础 Vue 推荐使用在绝大多数情况下使用 template 来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 templa ...

  10. 【Vue】详解Vue生命周期

    Vue实例的生命周期全过程(图) (这里的红边圆角矩形内的都是对应的Vue实例的钩子函数) 在beforeCreate和created钩子函数间的生命周期 在beforeCreate和created之 ...

随机推荐

  1. 用jQuery实现ajax总结以及跨域问题

    本文为作者原创,未经博主允许,不可转载 ajax请求的常用的参数设置: type:请求类型,"POST","GET",默认为geturl:发送请求的地址data ...

  2. 【TCP/IP详解 卷一:协议】第二十二章 TCP的坚持定时器

    这两章来到了TCP的定时器部分,在 TCP的超时与重传 和 TCP的三握四挥 我们介绍了 TCP的重传定时器 和 TCP的2MSL定时器. 本随笔介绍 防止返回ACK丢失的死锁情况 的 坚持定时器 和 ...

  3. C++ Boost在VS2015中的使用

    1.下载包 目录结构: 切换到上面的目录,然后运行 bootstrap.bat 执行完毕后会生成两个exe文件 继续执行 bjam.exe 结束后,目录如下 2.设置路径 测试 #include &q ...

  4. Spring boot 中Hibernate 使用

    spring.jpa.properties.hibernate.hbm2ddl.auto=有四种配置方式,分别如下: 是hibernate的配置属性,其主要作用是:自动创建.更新.验证数据库表结构.该 ...

  5. STL_算法_02_排序算法

    ◆ 常用的排序算法: 1.1.合并(容器A(全部/部分)&容器B(全部/部分)==>容器C(全部/部分),容器C中元素已经排好顺序),返回的值==>iteratorOutBegin ...

  6. c语言的左移和右移

    转自:https://www.cnblogs.com/myblesh/articles/2431806.html 先说左移,左移就是把一个数的所有位都向左移动若干位,在C中用<<运算符.例 ...

  7. IntelliJ IDE 开发Java GUI 入门

    j主要对java 的GUI相关知识进行简单的介绍和总结,整个博客按照创建一个java GUI的顺序进行介绍,期间穿插讲解用到的java Swing的布局.控件等相关知识.本博客所进行的讲解及工程的创建 ...

  8. Qt与FFmpeg联合开发指南(一)——解码(1):功能实现

    前言:对于从未接触过音视频编解码的同学来说,使用FFmpeg的学习曲线恐怕略显陡峭.本人由于工作需要,正好需要在项目中使用.因此特地将开发过程总结下来.只当提供给有兴趣的同学参考和学习. 由于FFmp ...

  9. NeteaseCloudWebApp模仿网易云音乐的vue自己从开源代码中学习到的

    github地址: https://github.com/javaSwing/NeteaseCloudWebApp 1.Vue.prototype.$http = Axios // 类似于vue-re ...

  10. js插件---Bootstrap 树控件

    js插件---Bootstrap 树控件 一.总结 一句话总结:可以直接用gojs,或者搜索js,jquery的树控件,或者bootstrap树控件,一大堆 gojs 二.JS组件系列——Bootst ...