- vue静态成员(Vue.set() Vue.use() Vue.extend().... )和实例成员(vm.$on vn.$emit...)初始化过程
- vue首次渲染的过程
- vue响应式机制
vue核心文件结构(src下)
- compiler (把template模板转换成render函数,render函数创建虚拟DOM)
-
core
1 components 定义了keep-alive组件
2 global-api 定义了vue静态方法 Vue.extend Vue.use ....
3 instance vue实例创建
4 observer 实现响应式
5 util 公共方法
6 vdom 虚拟DOM 重写了snabbdom - platforms 平台相关代码 1 web 2 weex
- server 服务端渲染相关
- sfc 把vue单文件组件转换成js对象
-
shared 功能代码
静态类型检查采用flow
打包工具采用Rollup ,比webpack轻,webpack把所有文件当做模块 ,rollup只处理js文件 更适合vue这样的js库开发,Rollup不会生成冗余代码
调试设置
- cnpm i 安装依赖
- 设置source-map "dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web-full-dev" 开启代码地图后在打断点会生成src源码目录,可以打开对应源码文件
- npm run dev打包
打包后的不同版本vue
- npm run build 编译打包不同版本的vue
完整版带编译器,可以把template转换为render函数,但体积大,运行时版本不带编译器(runtime) vue-cli运行使用的是vue.runtime.esm.js 运行时es版本,有tree-shaking功能 - vue-cli 可以使用 vue inspect > output.js可以输出webpack配置文件,但不能直接使用,可以查看配置参数,可以看到vue-cli导入的vue是vue.runtime.esm.js 版本
vue模板编译过程
- 模板编译主要是将模板转换为为render渲染函数的过程
作用
- vue2.0使用vnode描述视图和各种交互,用户自己编写vnode比较复杂
- 用户只需编写类型html代码模板,通过编译器将模板转换为返回vnode的render函数
- .vue文件会在webpack构建过程中被转换为render函数(通过vue-loader)
编译模板文件位置 src/platforms/web/entry-runtime-with-compile.js
- 首先判断用户传入的render是否存在
- 没有render继续判断是否存在template,有的话template为模板内容
- 没有判断是否选项中是否有el属性,有的话把el的outerHTMl作为模板,调用comlieToFunctions把template转化为render函数
模板编译的例子
- 编译前模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>compile</title>
</head>
<body>
<!--模板内容-->
<div id="app">
<h1>Vue<span>模板编译过程</span></h1>
<p>{{ msg }}</p>
<comp @myclick="handler"></comp>
</div>
<script src="../../dist/vue.js"></script>
<script>
Vue.component('comp', {
template: '<div>I am a comp</div>'
})
const vm = new Vue({
el: '#app',
data: {
msg: 'Hello compiler'
},
methods: {
handler () {
console.log('test')
}
}
})
console.log(vm.$options.render)
</script>
</body>
</html>
- 编译后的render函数内容
function anonymous() {
with (this) {
return _c('div', {
attrs: {
"id": "app"
}
},
[ _m(0),
_v(" "),
_c('p',
[_v(_s(msg))]),
_v(" "),
_c('comp', {
on: {
"myclick": handler
}
})], 1)
}
}
- _c('p',[_v(_s(msg))]), 创建p标签对应vnode,第二个参数为数组包含的文本,用户手写的render函数第二个参数可以直接是一个文本内容,会通过normizeChildren转化为这个数组形式
- with (this)可以让代码块中使用this的地方省略this
- 其中 _v _c _m都是this vue实例方法
- _c 是 createElement() 方法,定义的位置 src/core/instance/render.js 中
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
- _m _v _s,在 src/core/instance/render-helps/index.js 中
- _m 设置静态内容
- _v创建包含文本的vnode
- _s参数转化为字符串
export function installRenderHelpers (target: any) {
target._s = toString
target._m = renderStatic
target._v = createTextVNode
}
模板编译函数
- compileToFunctions: 把template编译为render函数 把生成的render记录到options属性中 src/platforms/web/entry-runtime-with-compile.js
- compileToFunctions : 在 src/platforms/web/compile/index中导出 createCompiler函数生成 参数baseOptions
- createCompiler src/complie/index.js定义
抽象语法树
- 使用对象形式描述树形代码结构,树形结构的html字符串
- 使用ast好处:
- 模板字符串转换为ast后,可以通过ast对模板进行优化
- 标记模板中的静态内容,在patch的时候跳过静态内容
- 在patch过程中静态内容不需要对比和重新渲染
组件化 一个用于预定义选项的vue实例
vue组件化
vue.component注册组件内部实现
- src/core/global-api/index.js initAssetRegisters定义
- 第二个参数为对象,会调用vue.extend,把组件配置转换为组件的构造函数
- 第二个参数为函数会把参数记录到options选项的components中
vue.extend
- src/core/global-api/extend.js
- 接受参数 组件的选项对象 通过传入的选项创建组件的构造函数,继承与vue的构造函数