createComponent
patch
合并配置
总结
生命周期函数会被合并为数组。
这种合并思想值得借鉴,本身有一套默认配置,合并传入的配置,达到定制化的目的。
生命周期
放一张经典的生命周期图
beforeCreate & created
_init
src/core/instance/init.js
Vue.prototype._init = function (options?: Object) {// ...initLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, 'beforeCreate')initInjections(vm) // resolve injections before data/propsinitState(vm)initProvide(vm) // resolve provide after data/propscallHook(vm, 'created')// ...}
beforeMount && mounted
mountComponent
src/core/instance/lifecycle.js
export function mountComponent (vm: Component,el: ?Element,hydrating?: boolean): Component {vm.$el = el// ...callHook(vm, 'beforeMount')let updateComponent/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {updateComponent = () => {const name = vm._nameconst id = vm._uidconst startTag = `vue-perf-start:${id}`const endTag = `vue-perf-end:${id}`mark(startTag)const 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 = () => {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 definednew Watcher(vm, updateComponent, noop, {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 hookif (vm.$vnode == null) {vm._isMounted = truecallHook(vm, 'mounted')}return vm}
子组件的mounted回调,在这个方法里。
对于同步渲染的子组件而言,mounted钩子函数的执行顺序也是先子后父。 ,mixin时,会先执行原来的钩子,后执行mixin的钩子。
const componentVNodeHooks = {// ...insert (vnode: MountedComponentVNode) {const { context, componentInstance } = vnodeif (!componentInstance._isMounted) {componentInstance._isMounted = truecallHook(componentInstance, 'mounted')}// ...},}
beforeUpdate & updated
beforeDestroy & destroyed
destroyed钩子函数执行顺序也是先子后父,和mounted过程一致。
activated & deactivated
activated 和 deactivated 钩子函数是专门为keep-alive组件定制的钩子。
总结
created钩子中能够拿到data、props、methods属性,mounted钩子中能够访问到DOM,destroyed钩子中可以做一些定时器销毁工作。
组件注册
全局注册
Vue.component('my-component',{})
局部注册
import HelloWorld from './components/HelloWorld';export default {components: {HelloWorld,}}
总结
通用基础组件一般全局注册,业务组件局部注册。
异步组件
普通异步组件
Vue.components('async-example', function(resole, reject) {// 特殊的 require 语法告诉webpack// 自动将编译后的代码分割成不同的块// 这些块将通过 Ajax 请求自动下载require(['./my-async-component'], resolve)})
webpack 2+ 支持了异步加载的语法糖:() => import(‘./my-async-component’)
此外还支持两种方式,Promise创建组件
Vue.component('async-webpack-example',() => import('./my-async-component'))
高级异步组件
const AsyncComp = () => ({// 需要加载的组件 promisecomponent: import('./async-component.vue'),// 加载中应当渲染的组件 同步载入进来的loading: LoadingComp,// 出错时渲染的组件error: ErrorComp,// 渲染加载中组件前的等待时间。 默认: 200ms。delay: 200,// 最长等待时间。超出此时间则渲染错误组件。默认:Infinitytimeout: 3000,})Vue.component('async-example', AsyncComp)
总结
异步组件实现有3种方式,高级异步组件实现了loading、resolve、reject、timeout4种状态。
异步组件的实现本质是2次渲染,除了0 delay的高级异步组件会渲染loading外,
其他第一次都是渲染生成注释节点,当异步组件获取成功后,再通过forceRender强制重新渲染
