美文网首页
Vue源码04-initState

Vue源码04-initState

作者: 熊少年 | 来源:发表于2020-05-25 10:59 被阅读0次

这一节我们将分析vue里面的各种初始化

options初始化

    vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
合并后的结果

beforeCreate: [ƒ]
components: {}
computed: {user: ƒ}
created: [ƒ]
data: ƒ mergedInstanceDataFn()
directives: {}
el: "#app"
filters: {}
methods: {handlerUser: ƒ}
mounted: [ƒ]
watch: {a: ƒ}
_base: ƒ Vue(options)

  • 通过mergeOptions初始化,mergeOptions讲解参考Vue源码02

生命周期初始化

  vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')

这里主要讲解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)
  }
}

这里对props,methods,data,computed,watch分别进行了处理

initProps
function initProps (vm: Component, propsOptions: Object) {
  const propsData = vm.$options.propsData || {}
  const props = vm._props = {}  // 挂载_props
 ...
  const keys = vm.$options._propKeys = []
  if (!isRoot) {
    toggleObserving(false)
  }
  for (const key in propsOptions) {
    keys.push(key)
    // 对prop的值的计算validateProp详细去看
    // 先采用propsData没有则取默认值
    const value = validateProp(key, propsOptions, propsData, vm) 
     ....
     defineReactive(props, key, value) // 添加响应式
    
    if (!(key in vm)) {
      proxy(vm, `_props`, key) // 代理,通过this直接访问
    }
  }
}
  • 全局挂载_props,
  • 对props的值,进行全局配置
  • 添加响应式
  • 添加代理
initData
  let data = vm.$options.data
  data = vm._data = typeof data === 'function'
    ? getData(data, vm)  // 函数执行后在赋值
    : data || {}
  const keys = Object.keys(data)
  while (i--) {
    const key = keys[i]
    .... 
    proxy(vm, `_data`, key) //代理
  }
 observe(data, true) // 添加响应式
  • 全局挂载_data
  • 对data进行处理,判断是否是函数还是对象
  • 添加代理
  • 添加响应式
initComputed
  const watchers = vm._computedWatchers = Object.create(null) // 创建watchers
 for (const key in computed) {
    const userDef = computed[key]
    const getter = typeof userDef === 'function' ? userDef : userDef.get
    ....
   if (!isSSR) {
      watchers[key] = new Watcher(  // 实例Watcher
        vm,
        getter || noop,
        noop,
        computedWatcherOptions // {lazy:true} 
      )
    }

    if (!(key in vm)) {
      defineComputed(vm, key, userDef) // 代理vm
    } 
    ....
  }
  // defineComputed
export function defineComputed (
  target: any,
  key: string,
  userDef: Object | Function
) {
  const shouldCache = !isServerRendering()

   sharedPropertyDefinition.get = shouldCache
      ? createComputedGetter(key)
      : createGetterInvoker(userDef)
    sharedPropertyDefinition.set = noop
   ...
   Object.defineProperty(target, key, sharedPropertyDefinition) //代理
}
// createComputedGetter
function createComputedGetter (key) {
  return function computedGetter () {
    const watcher = this._computedWatchers && this._computedWatchers[key] // 通过key拿到watcher
    if (watcher) {
      if (watcher.dirty) {
        watcher.evaluate() // 计算
      }
      if (Dep.target) {
        watcher.depend() // Sub搜集Watcher
      }
      return watcher.value
    }
  }
}
  • 添加_computedWatchers
  • 生成Watcher
  • 添加代理 {lazy:true} 不会立即查值
  • 在get的时候,通过控制dirty控制
initWatch
function initWatch (vm: Component, watch: Object) {
  for (const key in watch) {             // {a:handlerChange(old,newV){}}
    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)
    }
  }
}
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)  // 这里使用$watch
}

...
 Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: any,
    options?: Object
  ): Function {
    const vm: Component = this
    if (isPlainObject(cb)) {
      return createWatcher(vm, expOrFn, cb, options) // 对cb进行递归
    }
    options = options || {}
    options.user = true  // 设置user为true
    const watcher = new Watcher(vm, expOrFn, cb, options)  //实例
    if (options.immediate) {
        cb.call(vm, watcher.value)
    }
    return function unwatchFn () {
      watcher.teardown()  // 移除sub
    }
  }
  • 解析watch的参数
  • 设置options.user = true在执行run的时候 会返回oldval
initMethods
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)  // 挂载是vm实例上
  }
}
  • 添加代理
  • 绑定作用域

相关文章

网友评论

      本文标题:Vue源码04-initState

      本文链接:https://www.haomeiwen.com/subject/kqxqahtx.html