Vue的_render方法是实例的一个私有方法,用来把实例渲染成一个虚拟DOM
定义在 src/core/instance/render.js 文件中

Vue.prototype._render

  1. Vue.prototype._render = function (): VNode {
  2. const vm: Component = this
  3. const { render, _parentVnode } = vm.$options
  4. if (_parentVnode) {
  5. vm.$scopedSlots = normalizeScopedSlots(
  6. _parentVnode.data.scopedSlots,
  7. vm.$slots,
  8. vm.$scopedSlots
  9. )
  10. }
  11. // set parent vnode. this allows render functions to have access
  12. // to the data on the placeholder node.
  13. vm.$vnode = _parentVnode
  14. // render self
  15. let vnode
  16. try {
  17. // There's no need to maintain a stack because all render fns are called
  18. // separately from one another. Nested component's render fns are called
  19. // when parent component is patched.
  20. currentRenderingInstance = vm
  21. vnode = render.call(vm._renderProxy, vm.$createElement)
  22. } catch (e) {
  23. handleError(e, vm, `render`)
  24. // return error render result,
  25. // or previous vnode to prevent render error causing blank component
  26. /* istanbul ignore else */
  27. if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
  28. try {
  29. vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
  30. } catch (e) {
  31. handleError(e, vm, `renderError`)
  32. vnode = vm._vnode
  33. }
  34. } else {
  35. vnode = vm._vnode
  36. }
  37. } finally {
  38. currentRenderingInstance = null
  39. }
  40. // if the returned array contains only a single node, allow it
  41. if (Array.isArray(vnode) && vnode.length === 1) {
  42. vnode = vnode[0]
  43. }
  44. // return empty vnode in case the render function errored out
  45. if (!(vnode instanceof VNode)) {
  46. if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
  47. warn(
  48. 'Multiple root nodes returned from render function. Render function ' +
  49. 'should return a single root node.',
  50. vm
  51. )
  52. }
  53. vnode = createEmptyVNode()
  54. }
  55. // set parent
  56. vnode.parent = _parentVnode
  57. return vnode
  58. }

开发中手写render方法的场景比较少,而写的比较多的是template模板
在mounted方法实现中会把template编译成render方法

  1. <div id="app">
  2. {{ message }}
  3. </div>

相当于编写如下render函数

  1. render: function (createElement) {
  2. return createElement('div', {
  3. attrs: {
  4. id: 'app'
  5. },
  6. }, this.message)
  7. }

再回到_render函数中的render方法的调用

  1. vnode = render.call(vm._renderProxy, vm.$createElement)

render函数中的createElement方法就是vm.$createElement方法

initRender

  1. export function initRender (vm: Component) {
  2. vm._vnode = null // the root of the child tree
  3. vm._staticTrees = null // v-once cached trees
  4. const options = vm.$options
  5. const parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent tree
  6. const renderContext = parentVnode && parentVnode.context
  7. vm.$slots = resolveSlots(options._renderChildren, renderContext)
  8. vm.$scopedSlots = emptyObject
  9. // bind the createElement fn to this instance
  10. // so that we get proper render context inside it.
  11. // args order: tag, data, children, normalizationType, alwaysNormalize
  12. // internal version is used by render functions compiled from templates
  13. vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
  14. // normalization is always applied for the public version, used in
  15. // user-written render functions.
  16. vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
  17. // $attrs & $listeners are exposed for easier HOC creation.
  18. // they need to be reactive so that HOCs using them are always updated
  19. const parentData = parentVnode && parentVnode.data
  20. /* istanbul ignore else */
  21. if (process.env.NODE_ENV !== 'production') {
  22. defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
  23. !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
  24. }, true)
  25. defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
  26. !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
  27. }, true)
  28. } else {
  29. defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
  30. defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
  31. }
  32. }

vm.$createElement方法是在initRender方法中定义的
vm._c方法是在template编译成render函数时使用,vm.$createElement是用户手写render方法时使用;这两个方法支持的参数相同,并且内部都调用了createElement方法