Vue vm.$options 中的render
2020-10-30 本文已影响0人
Wendy81
new Vue({
el:'#app',
render: h => h(App),
})
vm.$options指的是:
{
el:'#app',
render: h => h(App),
}
在Vue.prototype._render 代码中我们可以看到:
var render = vm.$options.render;
实际上这个render指的就是上面实例化时的render函数
var vm = this;
var ref = vm.$options;
var render = ref.render;
Vue.prototype._render = function () {
var vm = this;
var ref = vm.$options;
var render = ref.render;
var _parentVnode = ref._parentVnode;
if (_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 self
var vnode;
try {
// 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 = vm;
vnode = render.call(vm._renderProxy, vm.$createElement);
console.log('render ---- 999')
console.log(vnode)
} 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 it
if (Array.isArray(vnode) && vnode.length === 1) {
vnode = vnode[0];
}
// 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
};
了解下面的vnode的实现:
try {
// 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 = vm;
vnode = render.call(vm._renderProxy, vm.$createElement);
}
现在数据流结构是:
step1:入口文件是main.js
/*------------main.js------------*/
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el:'#app',
render: h => h(App),
})
step2:组件App.vue
/*------------App.vue------------*/
<template>
<div id="app1">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
step3:组件App.vue中的组件HelloWorld
/*------------HelloWorld.vue------------*/
<template>
<div id="hello" class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
}
</script>
文件关数据流
image.png然后在_render函数中我们可以看到vnode生成的数据对象是:
1. main.js
-context: Vue {_uid: 0
-parent: null
VNode {
asyncFactory: undefined
asyncMeta: undefined
children: undefined
componentInstance: VueComponent {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
componentOptions: {propsData: undefined, listeners: undefined, tag: undefined, children: undefined, Ctor: ƒ}
context: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
data: {on: undefined, hook: {…}, pendingInsert: null}
elm: div#app1
fnContext: undefined
fnOptions: undefined
fnScopeId: undefined
isAsyncPlaceholder: false
isCloned: false
isComment: false
isOnce: false
isRootInsert: true
isStatic: false
key: undefined
ns: undefined
parent: null
raw: false
tag: "vue-component-1-App"
text: undefined
child: (...)
__proto__: Object
}
2. App.vue
-context: Vue {_uid: 1
-parent: VNode {tag: "vue-component-1-App", data: {…}, children: undefined, text: undefined, elm: div#app1, …}
VNode {
asyncFactory: undefined
asyncMeta: undefined
children: (2) [VNode, VNode]
componentInstance: undefined
componentOptions: undefined
context: VueComponent {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
data: {attrs: {…}}
elm: div#app1
fnContext: undefined
fnOptions: undefined
fnScopeId: undefined
isAsyncPlaceholder: false
isCloned: false
isComment: false
isOnce: false
isRootInsert: true
isStatic: false
key: undefined
ns: undefined
parent: VNode {tag: "vue-component-1-App", data: {…}, children: undefined, text: undefined, elm: div#app1, …}
raw: false
tag: "div"
text: undefined
child: (...)
__proto__: Object
}
3. HelloWorld.vue
-context: Vue {_uid: 2
-parent: VNode {tag: "vue-component-2-HelloWorld", data: {…}, children: undefined, text: undefined, elm: div#hello.hello, …}
VNode {
asyncFactory: undefined
asyncMeta: undefined
children: (8) [VNode, VNode, VNode, VNode, VNode, VNode, VNode, VNode]
componentInstance: undefined
componentOptions: undefined
context: VueComponent {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
data: {staticClass: "hello", attrs: {…}}
elm: div#hello.hello
fnContext: undefined
fnOptions: undefined
fnScopeId: undefined
isAsyncPlaceholder: false
isCloned: false
isComment: false
isOnce: false
isRootInsert: true
isStatic: false
key: undefined
ns: undefined
parent: VNode {tag: "vue-component-2-HelloWorld", data: {…}, children: undefined, text: undefined, elm: div#hello.hello, …}
raw: false
tag: "div"
text: undefined
child: (...)
__proto__: Object
}