Vue Render Function
1.渲染过程
Template => Render Function => Virtual DOM => Actual DOM
Template => Render Function
两种编译模式:
- 把模板直接传入Vue实例,Vue执行完整的编译,打包时连同编译器打包,压缩后约30KB
- 使用Vue CLI构建项目,用到webpack与vue-loader,vue-loader会预编译,压缩后约20KB
Render Function => Virtual DOM
渲染函数返回虚拟DOM
Virtual DOM => Actual DOM
Vue基于虚拟DOM生成真实DOM
2.虚拟DOM
真实DOM的节点与虚拟DOM的节点是一一对应的,虚拟DOM使用一个JS对象来表示真实DOM的一个Node,而操作JS对象远比操作DOM节点更加简单。
数据或视图发生变化时,Vue会比较变化前后虚拟DOM的不同点,根据虚拟DOM的不同点来更新真实DOM。
使用Vue Template Explorer可以查看渲染函数(查看Vue是如何转换虚拟DOM的)。
https://template-explorer.vuejs.org/
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
import { createCommentVNode as _createCommentVNode, createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock(_Fragment, null, [
_createCommentVNode("DOCTYPE html"),
_createElementVNode("html", { lang: "en" }, [
_createElementVNode("head", null, [
_createElementVNode("meta", { charset: "UTF-8" }),
_createElementVNode("title", null, "quickFixIndent")
]),
_createElementVNode("body", null, [
_createElementVNode("div", { id: "wrapper" }, [
_createElementVNode("header", null, [
_createElementVNode("textarea", {
placeholder: "before",
id: "before"
})
]),
_createElementVNode("main", null, [
_createElementVNode("input", {
id: "number",
type: "text",
placeholder: "indent number",
value: "2"
}),
_createElementVNode("button", { onclick: "solve()" }, "Get!")
]),
_createElementVNode("footer", null, [
_createElementVNode("textarea", {
placeholder: "after",
id: "after"
})
])
])
])
])
], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
}
// Check the console for the AST
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
3.渲染函数API
上图是调用一个渲染函数例子,render
函数接收一个参数h
, h
只是一种约定的简写表示超脚本(HyperScript),他没有什么特殊意义,只是就像超文本我们叫HTML一样,只是方便书写的表示形式而已。
h
函数接受三个参数,第一个是元素类型;第二是参数对象例如表示元素的attr属性,DOM属性之类的;第三个属性表示一些子节点,你可以调用h函数生成更多子节点。
第二个参数是可以省略的,第三参数很灵活可以是数组(表示子元素)、单纯的文本(表示标签)以及组件变量名(表示组件)。
4.动态渲染标签
编写一个组件,组件根据tags
属性在页面上输入相应的HTML标签
使用
document.createElement
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
使用component标签
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
使用渲染函数
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
效果:
5.动态渲染组件
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
6.渲染函数与响应系统
上图是Vue的响应性系统和渲染系统的运行流程,可以看到每个组件有自己的渲染函数,这个渲染函数实际上是运行在我们之前封装的autorun
函数中的,组件开始渲染时会把属性收集到依赖项中,当调用属性的setter方法,会触发watcher
执行重新渲染,因为渲染函数放在autorun
函数中,所以每当data数据发生变化,就会重新渲染。
每个组件都有自己独立的循环渲染系统,组件只负责自己的依赖项,这一特性对于你拥有大型组件树时是一个优势,你的数据可以在任何地方改变,因为系统知道数据与组件的对应关系,不会造成过度渲染问题,这一架构优势可以让我们摆脱一些优化工作。