生命周期之beforeCreated和created

640 阅读2分钟

这是我参与更文挑战的第6天,活动详情查看: 更文挑战

beforeCreated初始化界面前

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    ...设置Vue元素的uid唯一值,设置Vue对象的_isVue避免被观察
    ... 参数合并
    ... 初始化this._renderProxy属性,_self指向自己this
    initLifecycle(vm) // 初始化一些参数
    initEvents(vm) // 初始化事件
    initRender(vm) // 初始化渲染函数
    callHook(vm, 'beforeCreate') 
  }
}

initLifecycle的实现

export function initLifecycle (vm: Component) {
  const options = vm.$options
  let parent = options.parent
  // 找到父节点然后将当前元素和父节点进行关联
  if (parent && !options.abstract) {
    while (parent.$options.abstract && parent.$parent) {
      parent = parent.$parent
    }
    parent.$children.push(vm)
  }
    
  vm.$parent = parent
  vm.$root = parent ? parent.$root : vm
  vm.$children = []
  vm.$refs = {}
  vm._watcher = null
  vm._inactive = null
  vm._directInactive = false
  vm._isMounted = false
  vm._isDestroyed = false
  vm._isBeingDestroyed = false
}
  • initLifecycle主要是初始化一些参数,其中主要是对当前vue对象的parent元素进行了绑定,已经设置了$root的属性

initEvents的实现

export function initEvents (vm: Component) {
  vm._events = Object.create(null)
  vm._hasHookEvent = false
  const listeners = vm.$options._parentListeners
  if (listeners) {
    updateComponentListeners(vm, listeners)  // 更新组件的时间监听
  }
}
  • export function updateComponentListeners (
      vm: Component,
      listeners: Object,
      oldListeners: ?Object
    ) {
      target = vm
      updateListeners(listeners, oldListeners || {}, add, remove, createOnceHandler, vm) // 更新监听器
      target = undefined
    }
    
  • 作用:更新组件的事件监听

initRender的实现

export function initRender (vm: Component) {
  vm._vnode = null 
  vm._staticTrees = null 
  const options = vm.$options
  const parentVnode = vm.$vnode = options._parentVnode
  const renderContext = parentVnode && parentVnode.context
  
  vm.$slots = resolveSlots(options._renderChildren, renderContext)
  vm.$scopedSlots = emptyObject
   
   // 设置_c属性和$createElement属性的对应的方法
  vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
  vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
    
  const parentData = parentVnode && parentVnode.data
  // 给vm对象添加个响应式的对象,并进行验证提示
  if (process.env.NODE_ENV !== 'production') {
    defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
      !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
    }, true)
    defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
      !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
    }, true)
  } else {
    defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
    defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
  }
}

综上所述:在beforeCreated之前做的主要对一些参数的初始化,所以此时的时候 options中的data和this还未进行绑定


created数据已经绑定到this上

initInjections(vm) 
initState(vm)
initProvide(vm) 
callHook(vm, 'created') 
  • initInjections的实现

    • export function initInjections (vm: Component) {
        const result = resolveInject(vm.$options.inject, vm)  // 分解inject对象
        if (result) {
          toggleObserving(false)
          Object.keys(result).forEach(key => {
            if (process.env.NODE_ENV !== 'production') {
              defineReactive(vm, key, result[key], () => {
                warn(
                  `Avoid mutating an injected value directly since the changes will be ` +
                  `overwritten whenever the provided component re-renders. ` +
                  `injection being mutated: "${key}"`,
                  vm
                )
              })
            } else {
              defineReactive(vm, key, result[key])
            }
          })
          toggleObserving(true)
        }
      }
      
      • 循环将分解得到的inject绑定到this实例对象上
    • export function resolveInject (inject: any, vm: Component): ?Object {
        if (inject) {
          const result = Object.create(null)
          const keys = hasSymbol
            ? Reflect.ownKeys(inject) 
            : Object.keys(inject)
          for (let i = 0; i < keys.length; i++) {
            const key = keys[i]
            if (key === '__ob__') continue
            const provideKey = inject[key].from // 这个私钥是干啥用的呢?
            let source = vm
            // 这里不明白, 这个_provided是干什么的
            while (source) {
              if (source._provided && hasOwn(source._provided, provideKey)) {
                result[key] = source._provided[provideKey]
                break
              }
              source = source.$parent
            }
            if (!source) {
              if ('default' in inject[key]) {
                const provideDefault = inject[key].default
                result[key] = typeof provideDefault === 'function'
                  ? provideDefault.call(vm)
                  : provideDefault
              } else if (process.env.NODE_ENV !== 'production') {
                warn(`Injection "${key}" not found`, vm)
              }
            }
          }
          return result
        }
      }
      
      • 这个函数主要是分解inject对象,具体中间的内容需要之后进行整理
  • initState的实现

    • export function initState (vm: Component) { 
        vm._watchers = []
        const opts = vm.$options
        if (opts.props) initProps(vm, opts.props) 
        if (opts.methods) initMethods(vm, opts.methods) 
        if (opts.data) {
          initData(vm) 
        } else {
          observe(vm._data = {}, true /* asRootData */)
        }
        if (opts.computed) initComputed(vm, opts.computed) 
        if (opts.watch && opts.watch !== nativeWatch) {
          initWatch(vm, opts.watch)
        }
      }
      
      • $options参数中的props|methods|data |computed|initWatch属性进行初始化,应该是将这些对象中的数据直接和this实例对象进行绑定
    • function initProps (vm: Component, propsOptions: Object) {
        ....
        for (const key in propsOptions) {
          const value = validateProp(key, propsOptions, propsData, vm) // 获取指定格式的值
          if (process.env.NODE_ENV !== 'production') {
            ...格式化key,并进行验证
             // 将props中的key都设置成可以被监听的
            defineReactive(props, key, value, () => {
              if (!isRoot && !isUpdatingChildComponent) {
                warn(
                  `Avoid mutating a prop directly since the value will be ` +
                  `overwritten whenever the parent component re-renders. ` +
                  `Instead, use a data or computed property based on the prop's ` +
                  `value. Prop being mutated: "${key}"`,
                  vm
                )
              }
            })
          } else {
            defineReactive(props, key, value)
          }
          if (!(key in vm)) {
            proxy(vm, `_props`, key) 
          }
        }
        toggleObserving(true)
      }
      
    • function initMethods (vm: Component, methods: Object) {
        const props = vm.$options.props
        for (const key in methods) {
          .... 验证
          vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm) // 将方法绑定到this实例对象上
        }
      }
      
    • function initData (vm: Component) {
        let data = vm.$options.data
        const keys = Object.keys(data)
        ... 对于data中的数据进行校验判断是否已经在其他的methods/props中已被注册过了,如	果过了就提示,没有注册就进行注册,将代理到this._data[key]上
        observe(data, true /* asRootData */) // 对data中的数据进行观察
      }
      
    • function initComputed (vm: Component, computed: Object) {
        const watchers = vm._computedWatchers = Object.create(null)
        const isSSR = isServerRendering() //TODO:判断是否是服务渲染的
        for (const key in computed) {
          const userDef = computed[key]
          const getter = typeof userDef === 'function' ? userDef : userDef.get
        	...检查
          }
      
          if (!isSSR) {
            // 创建监听器,给computed做监听
            watchers[key] = new Watcher(
              vm,
              getter || noop,
              noop,
              computedWatcherOptions //{ lazy: true }
            )
          }
      
          if (!(key in vm)) { // 直接将computed中的属性绑定到了this对象上了
            defineComputed(vm, key, userDef) // 在vue实例对象上添加一个computed的key的属性进行set和get的监听事件
          }
           ...与其他属性进行验证判断是否名称重复了呢
        }
      }
      
      • 先循环获取computed中的自定义执行函数,然后对每个属性设置监听
      • 然后将每个computed属性绑定到this实例对象上
    • function initWatch (vm: Component, watch: Object) {
        for (const key in watch) {
          const handler = watch[key]
          if (Array.isArray(handler)) {
            for (let i = 0; i < handler.length; i++) {
              createWatcher(vm, key, handler[i]) // 生成监听器
            }
          } else {
            createWatcher(vm, key, handler)// 调用了$watch方法来将函数实现对元素的监听
          }
        }
      }
      
      function createWatcher (
        vm: Component,
        expOrFn: string | Function,
        handler: any,
        options?: Object
      ) {
        if (isPlainObject(handler)) {
          options = handler
          handler = handler.handler
        }
        if (typeof handler === 'string') {
          handler = vm[handler]
        }
        return vm.$watch(expOrFn, handler, options)
      }
      

综上所述:对于options中的属性都将属性直接绑定到了this实例对象上,并对属性都设置了响应式处理