vue.js 源代码学习笔记 ----- instance render

/* @flow */

import {
  warn,
  nextTick,
  toNumber,
  _toString,
  looseEqual,
  emptyObject,
  handleError,
  looseIndexOf
} from '../util/index'

import VNode, {
  cloneVNodes,
  createTextVNode,
  createEmptyVNode
} from '../vdom/vnode'

import { createElement } from '../vdom/create-element'
import { renderList } from './render-helpers/render-list'
import { renderSlot } from './render-helpers/render-slot'
import { resolveFilter } from './render-helpers/resolve-filter'
import { checkKeyCodes } from './render-helpers/check-keycodes'
import { bindObjectProps } from './render-helpers/bind-object-props'
import { renderStatic, markOnce } from './render-helpers/render-static'
import { resolveSlots, resolveScopedSlots } from './render-helpers/resolve-slots'

export function initRender (vm: Component) {
  vm.$vnode = null // the placeholder node in parent tree 站位节点
  vm._vnode = null // the root of the child tree 根节点
  vm._staticTrees = null
const parentVnode = vm.$options._parentVnode const renderContext = parentVnode && parentVnode.context vm.$slots = resolveSlots(vm.$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 templates
// 把创建元素 的函数绑定到这个实例上, 这样就能得到合适的渲染上下文;
// 参数的顺序是: 标签 数据 子节点 规范化的类型 是否总是规范化 vm._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) } export function renderMixin (Vue: Class<Component>) {
//定义 $nextTick函数, 实际调用了 nextTick方法 Vue.prototype.$nextTick
= function (fn: Function) { return nextTick(fn, this) } Vue.prototype._render = function (): VNode { const vm: Component = this const { render, staticRenderFns, _parentVnode } = vm.$options if (vm._isMounted) { // clone slot nodes on re-renders for (const key in vm.$slots) {
//克隆虚拟节点给自己 vm.$slots[key]
= cloneVNodes(vm.$slots[key]) } }
//scopedSlots ... vm.$scopedSlots
= (_parentVnode && _parentVnode.data.scopedSlots) || emptyObject if (staticRenderFns && !vm._staticTrees) { vm._staticTrees = [] }
// set parent vnode. this allows render functions to have access // to the data on the placeholder node.
  // 设置父虚拟节点, 这使得渲染函数可以访问站位节点上的数据

vm.$vnode = _parentVnode // render self let vnode
try { vnode = render.call(vm._renderProxy, vm.$createElement) } catch (e) { handleError(e, vm, `render function`)
// return error render result, // or previous vnode to prevent render error causing blank component /* istanbul ignore else */
    // 返回一个错误渲染的结果, 或者前一个虚拟节点放在呈现错误的时候引起空白组件
if (process.env.NODE_ENV !== 'production') { vnode = vm.$options.renderError ? vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e) : vm._vnode } else { vnode = vm._vnode } }
// return empty vnode in case the render function errored out
// 返回空的虚拟节点 假如渲染函数出错了 if (!(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 parent vnode.parent = _parentVnode return vnode } // internal render helpers. // these are exposed on the instance prototype to reduce generated render // code size.
// 用简写, 生成实例的时候减少代码
Vue.prototype._o = markOnce Vue.prototype._n = toNumber Vue.prototype._s = _toString Vue.prototype._l = renderList Vue.prototype._t = renderSlot Vue.prototype._q = looseEqual Vue.prototype._i = looseIndexOf Vue.prototype._m = renderStatic Vue.prototype._f = resolveFilter Vue.prototype._k = checkKeyCodes Vue.prototype._b = bindObjectProps Vue.prototype._v = createTextVNode Vue.prototype._e = createEmptyVNode Vue.prototype._u = resolveScopedSlots }
原文地址:https://www.cnblogs.com/dhsz/p/7116430.html