Vue的_render方法是实例的一个私有方法,用来把实例渲染成一个虚拟DOM
定义在 src/core/instance/render.js 文件中
Vue.prototype._render
Vue.prototype._render = function (): VNode {const vm: Component = thisconst { render, _parentVnode } = vm.$optionsif (_parentVnode) {vm.$scopedSlots = normalizeScopedSlots(_parentVnode.data.scopedSlots,vm.$slots,vm.$scopedSlots)}// set parent vnode. this allows render functions to have access// to the data on the placeholder node.vm.$vnode = _parentVnode// render selflet vnodetry {// There's no need to maintain a stack because all render fns are called// separately from one another. Nested component's render fns are called// when parent component is patched.currentRenderingInstance = vmvnode = render.call(vm._renderProxy, vm.$createElement)} catch (e) {handleError(e, vm, `render`)// return error render result,// or previous vnode to prevent render error causing blank component/* istanbul ignore else */if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {try {vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)} catch (e) {handleError(e, vm, `renderError`)vnode = vm._vnode}} else {vnode = vm._vnode}} finally {currentRenderingInstance = null}// if the returned array contains only a single node, allow itif (Array.isArray(vnode) && vnode.length === 1) {vnode = vnode[0]}// return empty vnode in case the render function errored outif (!(vnode instanceof VNode)) {if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {warn('Multiple root nodes returned from render function. Render function ' +'should return a single root node.',vm)}vnode = createEmptyVNode()}// set parentvnode.parent = _parentVnodereturn vnode}
开发中手写render方法的场景比较少,而写的比较多的是template模板
在mounted方法实现中会把template编译成render方法
<div id="app">{{ message }}</div>
相当于编写如下render函数
render: function (createElement) {return createElement('div', {attrs: {id: 'app'},}, this.message)}
再回到_render函数中的render方法的调用
vnode = render.call(vm._renderProxy, vm.$createElement)
render函数中的createElement方法就是vm.$createElement方法
initRender
export function initRender (vm: Component) {vm._vnode = null // the root of the child treevm._staticTrees = null // v-once cached treesconst options = vm.$optionsconst parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent treeconst renderContext = parentVnode && parentVnode.contextvm.$slots = resolveSlots(options._renderChildren, renderContext)vm.$scopedSlots = emptyObject// bind the createElement fn to this instance// so that we get proper render context inside it.// args order: tag, data, children, normalizationType, alwaysNormalize// internal version is used by render functions compiled from templatesvm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)// normalization is always applied for the public version, used in// user-written render functions.vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)// $attrs & $listeners are exposed for easier HOC creation.// they need to be reactive so that HOCs using them are always updatedconst parentData = parentVnode && parentVnode.data/* istanbul ignore else */if (process.env.NODE_ENV !== 'production') {defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {!isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)}, true)defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {!isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)}, true)} else {defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)}}
vm.$createElement方法是在initRender方法中定义的
vm._c方法是在template编译成render函数时使用,vm.$createElement是用户手写render方法时使用;这两个方法支持的参数相同,并且内部都调用了createElement方法
