(关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导)
Vue进阶系列汇总如下,欢迎阅读,欢迎加高级前端进阶群一起学习(文末)。
Vue 进阶系列(一)之响应式原理及实现
Vue 进阶系列(二)之插件原理及实现
Vue 进阶系列(三)之Render函数原理及实现
Render函数原理
根据第一篇文章介绍的响应式原理,如下图所示。
在初始化阶段,本质上发生在auto run
函数中,然后通过render
函数生成Virtual DOM
,view
根据Virtual DOM
生成Actual DOM
。因为render
函数依赖于页面上所有的数据data
,并且这些数据是响应式的,所有的数据作为组件render
函数的依赖。一旦这些数据有所改变,那么render
函数会被重新调用。
在更新阶段,render
函数会重新调用并且返回一个新的Virtual Dom
,新旧Virtual DOM
之间会进行比较,把diff之后的最小改动应用到Actual DOM
中。
Watcher负责收集依赖,清除依赖和通知依赖。在大型复杂的组件树结构下,由于采用了精确的依赖追踪系统,所以会避免组件的过度渲染。
Actual DOM 和 Virtual DOM
Actual DOM 通过document.createElement('div')生成一个DOM节点。
document.createElement('div')
// 浏览器原生对象(开销大)
"[object HTMLDivElement]"
Virtual DOM 通过 vm.$createElement('div')生成一个JS对象,VDOM对象有一个表示div的tag属性,有一个包含了所有可能特性的data属性,可能还有一个包含更多虚拟节点的children列表。
vm.$createElement('div')
// 纯JS对象(轻量)
{ tag: 'div', data: { attrs: {}, ...}, children: [] }
因为Virtual DOM的渲染逻辑和Actual DOM解耦了,所以有能力运行在的非浏览器环境中,这就是为什么Virtual DOM出现之后混合开发开始流行的原因,React Native 和 Weex能够实现的原理就是这个。
JSX和Template
JSX和Template都是用于声明DOM和state之间关系的一种方式,在Vue中,Template是默认推荐的方式,但是也可以使用JSX来做更灵活的事。
JSX更加动态化,对于使用编程语言是很有帮助的,可以做任何事,但是动态化使得编译优化更加复杂和困难。
Template更加静态化并且对于表达式有更多约束,但是可以快速复用已经存在的模板,模板约束意味着可以在编译时做更多的性能优化,相对于JSX在编译时间上有着更多优势。
实例1:实现example组件
要求使用如下
要求输出如下
0
1
2
上面这个需求可以通过render
函数来做,官方提供了createElement
函数用来生成模板。createElement('div', {}, [...])
可接受的参数如下。
// @returns {VNode}
createElement(
// {String | Object | Function}
// 一个 HTML 标签字符串,组件选项对象,或者
// 解析上述任何一种的一个 async 异步函数。必需参数。
'div',
// {Object}
// 一个包含模板相关属性的数据对象
// 你可以在 template 中使用这些特性。可选参数。
{
},
// {String | Array}
// 子虚拟节点 (VNodes),由 `createElement()` 构建而成,
// 也可以使用字符串来生成“文本虚拟节点”。可选参数。
[
'先写一些文字',
createElement('h1', '一则头条'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
)
知道了用法之后,就可以在render
中返回createElement
生成的虚拟节点,外层是div
,内层是三个锚点标题h1 h2 h3
,所以内层需要遍历下,使用两个createElement
就可以完成了。
通常使用h
作为createElement
的别名,这是Vue
的通用惯例,也是JSX
的要求。
实现如下
实例2:实现动态的
组件
要求如下
- 实现一个
Foo
组件渲染
,实现一个fooBar
组件渲染
。bar - 实现一个
组件,根据属性ok
动态渲染Foo
组件或者Bar
组件。如果属性ok
是true
,那么最终的渲染应该是
。foo - 实现一个按钮控制属性
ok
,通过这个属性让
在Foo
或者Bar
之间切换。
根据上面的要求,在模板中调用
组件,然后定义组件,同时绑定属性
ok
。
实现如下
实例3:实现组件
要求如下
- 实现一个
withAvatarURL
函数,要求传入一个带有url
属性的组件,返回一个接收username
属性的高阶组件,这个高阶组件主要负责获取相应的头像URL。 - 在API返回之前,高阶组件将占位符URL
http://via.placeholder.com/200x200
传递给内部组件。
例子如下
const SmartAvatar = withAvatarURL(Avatar)
// 使用这个方式
// 替换下面的方式
withAvatarURL
函数返回一个对象,接收username
属性,在生命周期created
获取头像URL。Avatar
对象接收src
属性,src
的内容从withAvatarURL
中获取,然后展示在上。实例化的时候,传入新定义的组件名SmartAvatar
。
实现如下
本文内容参考自VUE作者尤大的付费视频
Vue官网之渲染函数 & JSX
交流
本人Github链接如下,欢迎各位Star
http://github.com/yygmind/blog
我是木易杨,网易高级前端工程师,跟着我每周重点攻克一个前端面试重难点。接下来让我带你走进高级前端的世界,在进阶的路上,共勉!
如果你想加群讨论每期面试知识点,公众号回复[加群]即可