functionVue(options) { if (process.env,NODE_ENV !== 'production' && !(thisinstanceofVue)) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) } initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)
exportdefaultVue
Vue 初始化主要就干了以下几件事情: 合并配置、初始化生命周期、初始化事件中心、初始化渲染、初始化 data、props、computed、watcher等等。在初始化的最后,如果有检测到 el 属性,则调用 vm.$mount 方法挂在 vm, 挂载的目标就是把模版渲染成最终的 DOM
Vue 初始化主要就干了几件事情,合并配置、初始化生命周期、初始化事件、初始化渲染、执行 beforeCrate 钩子、初始化依赖注入内容、初始化 prop、methods、data、computed、watcher,解析组件配置上的 provide 对象,执行 created 钩子,最后 mount 挂载真实 DOM
Vue 实例挂载 - $mount
Vue 中是通过 $mount 实例方法去挂在 vm 的,$mount 方法的实现是和平台、构建方式相关
const idToTemplate = cached(id => { const el = query(id) return el && el.innerHTML })
const mount = Vue.prototype.$mount Vue.prototype.$mount = function(el?: string | Element, hydration?: boolean): Components { el = el && query(el)
if (el === document.body || el === document.documentElement) { process.env.NODE_ENV !== 'production' && warn( `Do not mount Vue to <html> or <body> - mount to normal elements instead` ) returnthis }
const options = this.$options if (!options.render) { let template = options.template if (template) { if (typeof template === 'string'){ if (template.charAt(0) === '#') { template = idToTemplate(template)
if (process.env.NODE_ENV !== 'production' && !template) { warn(`Template element not found or is empty: ${options.template}`, this) } } } elseif (template.nodeType) { template = template.innerHTML } else { if (process.env.NODE_ENV !== 'production') { warn('invalid template option:' template, this) } returnthis } } elseif (el) { template = getOuterHTML(el) }
if (template) { if (process.env.NODE_ENV !== 'production' && config.performance && mark) { mark('compile') }
exportfunctionmountComponent ( vm: Component, el: ?Element, hydrating?: boolean ): Component { vm.$el = el if (!vm.$options.render) { vm.$options.render = createEmptyVNode if (process.env.NODE_ENV !== 'production') { /* 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')
let updateComponent /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { updateComponent = () => { const name = vm._name const id = vm._uid const startTag = `vue-perf-start:${id}` const endTag = `vue-perf-end:${id}`
// 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 newWatcher(vm, updateComponent, noop, { before () { if (vm._isMounted && !vm._isDestroyed) { 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 }
Vue.prototype._render = function (): VNode { constvm: Component = this const { render, _parentVnode } = vm.$options
if (_parentVnode) { vm.$scopedSlots = normalizeScopedSlots( _parentVnode.data.scopedSlots, vm.$slots ) }
// 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`) // 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 } } // 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 instanceofVNode)) { 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 }
// src\core\instance\lifecycle.js Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { constvm: Component = this const prevEl = vm.$el const prevVnode = vm._vnode const restoreActiveInstance = setActiveInstance(vm) vm._vnode = vnode // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. if (!prevVnode) { // initial render vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false/* removeOnly */) } else { // updates vm.$el = vm.__patch__(prevVnode, vnode) } restoreActiveInstance() // update __vue__ reference if (prevEl) { prevEl.__vue__ = null } if (vm.$el) { vm.$el.__vue__ = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. }