1 |
|
2 |
|
3 | import {
|
4 | warn,
|
5 | nextTick,
|
6 | emptyObject,
|
7 | handleError,
|
8 | defineReactive
|
9 | } from '../util/index'
|
10 |
|
11 | import { createElement } from '../vdom/create-element'
|
12 | import { installRenderHelpers } from './render-helpers/index'
|
13 | import { resolveSlots } from './render-helpers/resolve-slots'
|
14 | import { normalizeScopedSlots } from '../vdom/helpers/normalize-scoped-slots'
|
15 | import VNode, { createEmptyVNode } from '../vdom/vnode'
|
16 |
|
17 | import { isUpdatingChildComponent } from './lifecycle'
|
18 |
|
19 | export function initRender (vm: Component) {
|
20 | vm._vnode = null
|
21 | vm._staticTrees = null
|
22 | const options = vm.$options
|
23 | const parentVnode = vm.$vnode = options._parentVnode
|
24 | const renderContext = parentVnode && parentVnode.context
|
25 | vm.$slots = resolveSlots(options._renderChildren, renderContext)
|
26 | vm.$scopedSlots = emptyObject
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
|
32 |
|
33 |
|
34 | vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
|
35 |
|
36 |
|
37 |
|
38 | const parentData = parentVnode && parentVnode.data
|
39 |
|
40 |
|
41 | if (process.env.NODE_ENV !== 'production') {
|
42 | defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
|
43 | !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
|
44 | }, true)
|
45 | defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
|
46 | !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
|
47 | }, true)
|
48 | } else {
|
49 | defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
|
50 | defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
|
51 | }
|
52 | }
|
53 |
|
54 | export let currentRenderingInstance: Component | null = null
|
55 |
|
56 |
|
57 | export function setCurrentRenderingInstance (vm: Component) {
|
58 | currentRenderingInstance = vm
|
59 | }
|
60 |
|
61 | export function renderMixin (Vue: Class<Component>) {
|
62 |
|
63 | installRenderHelpers(Vue.prototype)
|
64 |
|
65 | Vue.prototype.$nextTick = function (fn: Function) {
|
66 | return nextTick(fn, this)
|
67 | }
|
68 |
|
69 | Vue.prototype._render = function (): VNode {
|
70 | const vm: Component = this
|
71 | const { render, _parentVnode } = vm.$options
|
72 |
|
73 | if (_parentVnode) {
|
74 | vm.$scopedSlots = normalizeScopedSlots(
|
75 | _parentVnode.data.scopedSlots,
|
76 | vm.$slots,
|
77 | vm.$scopedSlots
|
78 | )
|
79 | }
|
80 |
|
81 |
|
82 |
|
83 | vm.$vnode = _parentVnode
|
84 |
|
85 | let vnode
|
86 | try {
|
87 |
|
88 |
|
89 |
|
90 | currentRenderingInstance = vm
|
91 | vnode = render.call(vm._renderProxy, vm.$createElement)
|
92 | } catch (e) {
|
93 | handleError(e, vm, `render`)
|
94 |
|
95 |
|
96 |
|
97 | if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
|
98 | try {
|
99 | vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
|
100 | } catch (e) {
|
101 | handleError(e, vm, `renderError`)
|
102 | vnode = vm._vnode
|
103 | }
|
104 | } else {
|
105 | vnode = vm._vnode
|
106 | }
|
107 | } finally {
|
108 | currentRenderingInstance = null
|
109 | }
|
110 |
|
111 | if (Array.isArray(vnode) && vnode.length === 1) {
|
112 | vnode = vnode[0]
|
113 | }
|
114 |
|
115 | if (!(vnode instanceof VNode)) {
|
116 | if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
|
117 | warn(
|
118 | 'Multiple root nodes returned from render function. Render function ' +
|
119 | 'should return a single root node.',
|
120 | vm
|
121 | )
|
122 | }
|
123 | vnode = createEmptyVNode()
|
124 | }
|
125 |
|
126 | vnode.parent = _parentVnode
|
127 | return vnode
|
128 | }
|
129 | }
|