文本将对Vue的mounted阶段进行解析。使用的测试代码和之前的一样。vue版本v2.5.17-beta.0
测试代码:
<div id="box">
I love vue
<ul>
<li v-for="item in data" @click="logChange(item.NAME,item.AGE)">
{
{item.NAME}}
</li>
</ul>
</div>
//js
new Vue({
el: '#box',
data: {
data:[
{
NAME:'SDF',AGE:3},
{
NAME:'JIKU',AGE:6},
{
NAME:'HYF',AGE:3}
]
},
methods: {
logChange: function(name,age) {
console.log(name,age);
}
}
});
在得到渲染函数后,就可以执行它生成虚节点。这就是在mounted
阶段完成的,来看以下代码。
一、创建监听器对象
function mountComponent (
vm,
el,
hydrating
) {
vm.$el = el;
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode;
{
/* istanbul ignore if */
if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
vm.$options.el || el) {
warn(
'You are using the runtime-only build of Vue where the template ' +
'compiler is not available. Either pre-compile the templates into ' +
'render functions, or use the compiler-included build.',
vm
);
} else {
warn(
'Failed to mount component: template or render function not defined.',
vm
);
}
}
}
callHook(vm, 'beforeMount');
var updateComponent;
/* istanbul ignore if */
if ("development" !== 'production' && config.performance && mark) {
updateComponent = function () {
var name = vm._name;
var id = vm._uid;
var startTag = "vue-perf-start:" + id;
var endTag = "vue-perf-end:" + id;
mark(startTag);
var vnode = vm._render();
mark(endTag);
measure(("vue " + name + " render"), startTag, endTag);
mark(startTag);
vm._update(vnode, hydrating);
mark(endTag);
measure(("vue " + name + " patch"), startTag, endTag);
};
} else {
updateComponent = function () {
vm._update(vm._render(), hydrating);
};
}
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
new Watcher(vm, updateComponent, noop, {
before: function before () {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate');
}
}
}, true /* isRenderWatcher */);
hydrating = false;
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
vm._isMounted = true;
callHook(vm, 'mounted');
}
return vm
}
这里通过创建一个监听器Watcher
来执行渲染函数。
即:
new Watcher(vm, updateComponent, noop, {
before: function before () {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate');
}
}
}, true /* isRenderWatcher */);
这个监听器函数最终会执行updateComponent
回调
updateComponent = function () {
vm._update(vm._render(), hydrating);
};
二、执行Vue实例的_render
函数,并执行渲染函数
Vue.prototype._render = function () {
var vm = this;
var ref = vm.$options;
var render = ref.render;
var _parentVnode = ref._parentVnode;
// reset _rendered flag on slots for duplicate slot check
{
for (var key in vm.$slots) {
// $flow-disable-line
vm.$slots[key]._rendered = false;
}
}
if (_parentVnode) {
vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject;
}
// set parent vnode. this allows render functions to have access
// to the data on the placeholder node.
vm.$vnode = _parentVnode