render 函数
什么是 Vritual DOM?
Virtual DOM 是vue2.0以后才引入的概念,一个真实的DOM他的操作性能是比较高的,一个div元素的第一层key,就有将近300个属性,Virtual DOM 是用 JavaScript 对象来表示 DOM 信息和结构,也就是在js和DOM之间做了一层缓存,去操作一个VDOM的代价自然是要小于操作一个真实DOM的,而对于真实DOM的任何细微操作都有可能引起页面的 重绘回流 ,从性能的角度出发,这是我们不愿意看到的情况,所以通过对象模拟出来的DOM结构,我们可以对他先进行操作,最后统一把修改映射到真实DOM上。Vue2.0的Virtual DOM参考自 snabbdom 。
virtual DOM相比真是DOM的优势
- 虚拟 DOM 不会立刻进行 回流与重绘 操作
- 虚拟 DOM 进行频繁修改,然后一次性比较并修改真实 DOM 中需要改的部分,最后在真实 DOM 中进行排版与重绘,减少过多DOM节点排版与重绘损耗
- 虚拟 DOM 有效降低大面积真实 DOM 的重绘与排版,因为最终与真实 DOM 比较差异,可以只渲染局部
vm._render()
承接 数据驱动流程分析(2)
挂载方法vm._update(vm._render(), hydrating)中的vm._render()函数
vm._render()最终会返回一个 VNode,并传入vm._update()函数
// src/croe/instance/render.js
Vue.prototype._render = function (): VNode {
const vm: Component = this
const { render, _parentVnode } = vm.$options
// ...
try {
// ...
vnode = render.call(vm._renderProxy, vm.$createElement)
} catch (e) {
// ...
}
// ...
return vnode
}
_render() 方法的核心部分是 vnode =(vm._renderProxy, vm.$createElement) ,即vm._renderProxy来调用render方法,并传入vm.$createElement作为参数
看一下vm._renderProxy 是如何定义的
// src/core/instance/init.js
if (process.env.NODE_ENV !== 'production') {
// 开发环境下会实例化一个 proxy
initProxy(vm)
} else {
// 生产环境下 vm._renderProxy 实际上就是 vm本身
vm._renderProxy = vm
}
hasProxy是用于判断当前浏览器环境是否支持Proxy这个方法
// src/core/instance/proxy.js
initProxy = function initProxy (vm) {
if (hasProxy) {
// determine which proxy handler to use
const options = vm.$options
const handlers = options.render && options.render._withStripped
? getHandler
// 执行了hasHandler
: hasHandler
vm._renderProxy = new Proxy(vm, handlers)
} else {
vm._renderProxy = vm
}
}
// ....
const hasHandler = {
has (target, key) {
const has = key in target
const isAllowed = allowedGlobals(key) ||
(typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data))
if (!has && !isAllowed) {
if (key in target.$data) warnReservedPrefix(target, key)
// 如果访问了不存在于vm上的属性,则触发warnNonPresent
else warnNonPresent(target, key)
}
return has || !isAllowed
}
}
// ...
// 这个报错是常见的错误,一般我们访问data中未定义的数据时便会报这个错
const warnNonPresent = (target, key) => {
warn(
`Property or method "${key}" is not defined on the instance but ` +
'referenced during render. Make sure that this property is reactive, ' +
'either in the data option, or for class-based components, by ' +
'initializing the property. ' +
'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
target
)
}