侧边栏壁纸
  • 累计撰写 14 篇文章
  • 累计创建 15 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

Vue2 核心原理部分分析

xrdev
2022-09-08 / 0 评论 / 0 点赞 / 59 阅读 / 829 字 / 正在检测是否收录...

Vue 核心原理精简

init 初始化Vue 原型上方法

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

Vue.prototype._init Vue/VueComponent 构造函数调用的唯一方法

初始化Vue组件

initLifecycle(vm)

  1. while parent.$parent 绑定parent
  2. 初始化$parent, $children, $refs 变量
  3. 初始化$root 判断有没有parent , 没有就绑定到vm

initEvents(vm)

  1. TODO updateListerner

callHook(vm, 'beforeCreate') 调用 beforeCreate生命周期

initState(vm)

  1. initProps(vm)
    1.
  2. initData(vm)
    1. 遍历$options.data
      1. vm._data = $data
      2. 如果是函数就执行 data.call(vm) 绑定到当前实例vm
      3. Object.keys 遍历 key
      4. 判断 prop 里面有没有key, 有key 就不绑定到 vm 上
      5. proxy(vm, keys[i])
        1. Object.defineProperty 把 $data 里面所有属性绑定到 this 实例上
        2. set, get() 处理 vm._data 里面属性
      6. observe(data)
        1. new Observer(data)
  3. initComputed(vm)
  4. initMethods(vm)
  5. initWatch(vm)

callHook(vm, 'created')

initRender(vm)

  function initRender (vm: Component) {
    // *** 
    vm._renderContext = vm.$options._parentVnode && vm.$options._parentVnode.context
    vm.$slots = resolveSlots(vm.$options._renderChildren, vm._renderContext)
    vm.$createElement = bind(createElement, vm)
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)  // 挂载元素到vue 实例上。开始执行渲染方法
    }
  }
  vm.$mount == Vue.prototype._mount

Vue.prototype._mount 挂载元素

会调用 beforeMount mounted


  callHook(vm, 'beforeMount')
  vm._watcher = new Watcher(vm, () => { // 这件箭头回调函数回立即执行, expOrFun 这里会在Watcher 里最后一行的this.get() 中被调用 
    vm._update(vm._render(), hydrating) // _render 会调用 编译dom 字符串的js(里面如果使用到data里面的值,就会调用Object.defineProperty 里面的get 进行 `依赖收集` 。 
  }, noop)

lifecycleMixin 初始化一些的生命周期函数

Observer

constructor(value)

this.dep = new Dep()

判断value 为数组的话就, 绑定 arrayMethods vue 处理好重写push。。。等方法的数组的原型

observerArray 遍历数组, 给所有属性绑定observe

walk 处理所有非数组的值

  • defineReactive 遍历 obj[key]

    • dep = new Dep()
    • defineProperty get 被使用的话,回进入到这里
      • 取值
      • Dep.target 构造函数静态属性 target 有值的情况下 调用dep.depend 方法 ,然后放在 Dep.target.addDep(this)(这里的Dep.target 通常是Watcher实例)
    • defineProperty set
      • 取value 判断是否呵newVal相等, 如果相等就return
      • 设置值value ; setter.call(obj, newVal)
      • observe(neVal) 重新监听新值
      • dep.notify()

Dep

subs: Array; 依赖数组

depend () {
  if (Dep.target) {
    Dep.target.addDep(this) // 将当前dep 添加到Watcher 实例中
  }
}

notify() 会处理当前实例的所有的subs (Watcher实例) .update() 方法

Watcher

通常 watch , $watch 会使用到这对象

constructor (
    vm: Component, // 实例
    expOrFn: string | Function, // mounted 之前会传函数过来
    cb: Function, // 回调函数
    options?: Object = {}
)
this.getter = expOrFn//  判断是否为函数如果为函数就直接复赋值,否则为String 调用`parsePath(expOrFn)` 再赋值为this.getter

this.value = this.lazy
      ? undefined
      : this.get() // this.get() 会执行依赖收集的方法


get () {
  pushTarget(this) // 将当成watcher 实例,赋值为Dep.target静态属性上
  const value = this.getter.call(this.vm, this.vm) // (在mounted之前的expOrFn)执行这个方法会调用实例上的_render 方法,从而会渲染到dom,这样就回调用data 里面的 get 方法, 然后就会获取到Dep
  if (this.deep) { // 深度监听vue
    traverse(value)
  }
  popTarget() // 取消赋值到 Dep.target = null
  this.cleanupDeps()
  return value
}


addDep (dep: Dep) {
    const id = dep.id 
    if (!this.newDepIds.has(id)) {
      this.newDepIds.add(id)  
      this.newDeps.push(dep) // 
      if (!this.depIds.has(id)) {
        dep.addSub(this) // Dep 对象添加当前 Watcher 实例
      }
    }
  }
0

评论区