来源 刘涛

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. 【jdk源码分析】java.lang.Appendable

    1.概述 public interface Appendable 能够被添加 char 序列和值的对象.如果某个类的实例打算接收取自 Formatter 的格式化输出,那么该类必须实现 Appenda ...

  2. C#下载歌词文件

    前段时间写了一篇c#解析Lrc歌词文件,对lrc文件进行解析,支持多个时间段合并.本文借下载歌词文件来探讨一下同步和异步方法. Lrc文件在网络上随处可见,我们可以通过一些方法获取,最简单的就是别人的 ...

  3. 解决Ubuntu14.04 下 E: Encountered a section with no Package: header 问题

    参考: ubuntu-E:Encountered a section with no Package: header的解决办法 解决Ubuntu14.04 下 E: Encountered a sec ...

  4. 样本打散后计算单特征 NDCG

    单特征 NDCG 能计算模型的 NDCG,也就能计算单特征的 NDCG,用于评估单特征的有效性,跟 Group AUC 用途一样 单特征 NDCG 如何衡量好坏 如果是 AUC,越大于或小于 0.5, ...

  5. Jmeter 4.0 扩展插件

    今天发现Jmeter4.0 也可以安装插件 而且比之前的版本的安装方法更为容易 https://jmeter-plugins.org/ https://jmeter-plugins.org/insta ...

  6. Python day21模块介绍4(logging模块,configparser模块)

    1.日志等级从上往下依次降低 logging.basicConfig(#日志报错打印的基础配置 level=logging.DEBUG, filename="logger.log" ...

  7. select exists 的应用一例

    当遇到多层exists的时候,事情就变得开始复杂了.我们来看看这个例子吧 假设有三张表 选课表:学号.课程号 学生表:学号.姓名 课程表:课程号.课程名 请选出选了所有课程的学生 SELECT 姓名 ...

  8. English trip -- VC(情景课)1 C What's your name?(review)

    Xu言: 今天,阴差阳错又上了一次 VC 1 C的课,不过这次是小班的形式.这次课的教室叫 toronto   [təˈrɒntəʊ]  to ron to (多伦多(加拿大城市))   - -0我还 ...

  9. php安装redis扩展全

    一.安装redis mac 下安装也可以使用 homebrew,homebrew 是 mac 的包管理器. 1.执行 brew install redis 2.启动 redis,可以使用后台服务启动  ...

  10. iOS UI-IOS开发中Xcode的一些使用技巧

    一.快捷键的使用 经常用到的快捷键如下: 新建 shift + cmd + n     新建项目 cmd + n             新建文件 视图 option + cmd + 回车 打开助理编 ...