前言
本文详细的介绍了render是什么?render的作用是什么?以及虚拟DOM的好处是什么?还有些小demo可以测试一下
你知道的越多,你不知道的越多
点赞
再看,手留余香,与有荣焉
render()函数
什么是render?
简单粗暴的理解: render的作用就是来渲染虚拟DOM的
main.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h=>h(App)
}).$mount('#app')
render是一个配置项,它的作用是指定渲染函数,这里采用是的箭头函数的简写格式,完整的写法如下:
render: function(h) { return h(APP) }
-
上面的h只是一个形参, 在执行reader时会自动传入实参。
-
$mount的作用是Vue实例挂载在
<div id="app">
的元素中 -
$mount的作用是把前面产生的vue实例挂载到一个id名为#app的dom元素上。
-
在本项目,这个dom就是public/index.html中的#app
-
下面两种写法是等价:
new Vue({}).$mount('#app') <====> new Vue({el: '#app})
认识render
查看自动生成的render
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<ul><li>123</li></ul>
<p>{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 'vue'
}
})
// 上面的代码中,我们并没有指定渲染函数,但是,vue会自动 把el解析成渲染函数
console.log(vm.$options.render)
// with(this): 绑定this
// _C :是一个函数。用来创建虚拟dom.
// (function anonymous() {
// with(this){
// return _c('div',{
// attrs:{
// "id":"app"
// }
// },
// [
// _c('p', [ _v(_s(msg))] )
// ]
// )
// }
// })
</script>
</body>
</html>
基本格式
在组件中,它就是一个配置项,与data,methods,computed,created一样。
{
data(){},
methods:{},
// h 是一个形参
render(h){
return h(参数1,参数2,参数3);
// 参数1: String | Object | Function
// 是一个html标签,或者是一个组件,或者是一个函数
// 参数2:Object。是对参数1所表示的对象的设置。
// 参数3:参数1表示的对象的子对象。
}
}
形参
在render()被调用时,vue会自动传入一个实参 给h。这个实参是一个函数(createElement),在组件内部,我们也可以通过this.$createElement
来获取它。
Vue.component("com2",{
data(){
return {title:"com1"}
},
render(h){
console.log(this.$createElement === h); //true
return h('h2',[`vue-`,this.title])
},
mounted(){
console.log(this.$createElement)
}
})
返回值
render()方法使用传入的h函数来创建一个东东,然后再返回出去,那么,这个东东是什么?为什么它能起到和template一样的效果?
结论是:vnode,也就是我们说的虚拟dom.
它更准确的名字可能是
createNodeDescription
,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为“VNode”。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。
宏观理解Vue的工作过程
把模板解析成AST(抽象语法树);
AST编译成渲染函数
渲染函数结合数据生成虚拟Dom树
Vue的应用程序的主要工作步骤:
-
模板通过编译生成AST
-
由AST生成Vue的
render
函数(渲染函数) -
渲染函数结合数据生成Virtual DOM树,Diff和Patch后生成新的UI。
-
模板:Vue的模板基于纯HTML,基于Vue的模板语法,我们可以比较方便地声明数据和UI的关系(template标签下的内容;el中指定的内容)。
-
AST:AST是Abstract Syntax Tree的简称(抽象语法树),Vue使用HTML的Parser将HTML模板解析为AST,并且对AST进行一些优化的标记处理,提取最大的静态树,方便Virtual DOM时直接跳过Diff。
-
渲染函数:渲染函数是用来生成Virtual DOM的。Vue推荐使用模板来构建我们的应用界面,在底层实现中Vue会将模板编译成渲染函数,当然我们也可以不写模板,直接写渲染函数,以获得更好的控制 (这部分是我们今天主要要了解和学习的部分)。
- 方法一: vue通过你提供的template来自动生成
- 方法二: 直接指定render配置项。
-
Virtual DOM:虚拟DOM就是使用js的object模拟真实的dom,当状态(data)发生变化,更新之前做diff(对比新旧虚拟dom),达到最少操作dom的效果。Vue的Virtual DOM Patching算法是基于 Snabbdom 的实现,并在些基础上作了很多的调整和改进。
<!-- 真实dom -->
<div id="app">
<p>节点1</p>
</div>
<script>
<!--虚拟dom -->
const vnode = {
tag: 'div',
data: {id: 'app'},
children: {
tag: 'p',
data: {},
children: '节点1'
}
}
</script>
- Watcher:每个Vue组件都有一个对应的
watcher
,这个watcher
将会在组件render
的时候收集组件所依赖的数据,并在依赖有更新的时候,触发组件重新渲染。
- template,el的作用是用来生成渲染函数。
- 用 渲染函数 + 当前数据 ====> 虚拟DOM
- 虚拟DOM ===>真实的dom
通过 render函数把整个过程分成两部分:
- 编译期: 将Vue的模板转换为渲染函数
- 运行时:主要是基于渲染函数生成Virtual DOM树,并实时观测数据的变化,一旦数据变化了,重新调渲染函数生成新的虚拟DOM,并与旧虚拟DOM树相比,找出其中的区别,更新到真实DOM上。
如果直接指定render函数,就省略了模板的编译过程,vue运行的更快
定义渲染函数的三种方式
渲染函数(数据) ====》 视图
- el: (间接定义)在定义vue实例时使用,vue会解析其中的内容生成渲染函数。定义组件时不能使用。
- template:(间接定义) 在定义组件时使用。vue会解析其中的内容生成渲染函数。也是官方推荐的方式。
- 直接写render。特殊情况下,灵活使用,难度较大。 例子:
<div id="app">
<div>{{msg}}</div>
</div>
<script type="text/javascript">
var vm = new Vue({
data:{ msg: 'vue' },
el: "#app",
template: `<div>template</div>`,
render (h) {
return h("div", 'render')
}
})
// 可以通过如下代码来查看当前vue实例的render
console.log( vm.$options.render )
</script>
上面通过el,template,或者render其实都会指定渲染函数,前面两个是vue自动解析的,render配置是给我们一个机会:直接自已定制render函数。
图示:
特别地,在单独使用template和render时(不写el),要通过$mount()把vue实例挂载到指定的dom
var vm = new Vue({
data:{ msg: 'vue' },
render (h) {
return h("div", 'render')
}
})
vm.$mount('#app')
这三种方法的优先级是:
render > tempalte > el
观察整个Vue的工作过程
示例代码
<div id="app">
<p v-for="item in list">{{item}}</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
list: ['html', 'css', 'js']
}
})
</script>
- 模板
- 渲染函数
- 数据
- 真实DOM
什么是虚拟DOM?
就是js中的对象来模拟真实的DOM,当状态(data)发生变化,想要更快的知道哪些DOM节点发生变化,通过虚拟DOM检测哪些发生变化,再更新到真实的DOM上,可以理解为就是一个js对象
虚拟DOM的好处?
- 我们知道访问DOM是非常昂贵的,会造成相当多得性能浪费,所以我们试想,当某个状态发生变化时,只更新与这个状态相关联的DOM节点
- 虚拟DOM可以跨平台
createElement
render()是依赖于createElement来创建虚拟dom的,所以,我们要来具体学习它的用法。
功能
创建虚拟dom(VNode)。
格式
createElement h(参数1,参数2,参数3);
// 参数1: String | Object | Function
// 是一个html标签,或者是一个组件,或者是一个函数
// 参数2:Object。是对参数1所表示的对象的设置。
// 参数3:参数1表示的对象的子对象。理解为html标签中的子标记(如:ul下的li)
参数1
取值有三种可能:{String | Object | Function}
第一个参数对于createElement
而言是一个必须的参数,这个参数可以是字符串string
、是一个对象object
,也可以是一个函数function
。
下面是对应的示例:
字符串
取值有三种可能:{String | Object | Function}
第一个参数对于createElement
而言是一个必须的参数,这个参数可以是字符串string
、是一个对象object
,也可以是一个函数function
。
下面是对应的示例:
Vue.component('custom-element', {
render(h) {
return h('div')
}
})
产生一个空标签<div></div>
对象 (就是一个组件对象) , main.js中就是这种写法
Vue.component('custom-element', {
render(h){
return h({
template: `<h2>{{title}}</h2>`,
data(){return{title:"vue"}}
})
}
})
得到的真实dom:<h2>vue</h2>
函数
在这个函数中返回一个组件。
Vue.component('custom-element', {
render: function (createElement) {
var eleFun = function () {
return {
template: `<div>Hello Vue!</div>`
}
}
return createElement(eleFun())
}
})
参数2
参数2是一个对象,它用来表示对参数1的描述。它是可选的。
{
class:{ className1 : true, className2: true},
style:{
color: 'red',
fontSize:'20px'
....
},
// 正常的HTML特性
attrs:{
id:"yourId"
},
// 组件的props
props:{
},
// DOM属性
domProps:{
innerHTML: "baz"
},
// 事件,this.$emit
on:{
click: this.hClick,
customEvent:this.hCustomEvent,
......
},
// 原生事件
nativeOn:{
click: this.nativeClickHandler
},
directives:[{
name:"",
value:"",
expression: "1 + 1",
arg:'foo',
modifiers:{bar:true}
}]
}
参数3
格式是字符串或数组。用来表示子内容。
理解为ul中的li:ul是父级节点,li是子级节点
它有两种格式:
- 字符串。它最终会渲染成元素的内容。
- 数组。它最终会在为元素的子节点
render(h){
return h("div",{class:"a"},[h('span','span的内容'),h('p','p的内容')])
},
对应生成的dom结构是:
<div class="a"><span>span的内容</span><p>p的内容</p></div>
ps:
如果内容有错误的地方欢迎指出(觉得看着不理解不舒服想吐槽也完全没问题);如果有帮助,欢迎点赞和收藏,转载请著明出处,如果有问题也欢迎私信交流