Skip to content

ganlt/vue-understand

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vue的响应式数据原理

Vue运行机制解析图new Vue()之后,Vue会调用_init进行数据初始化,他会初始化生命周期、事件、props、methods、data、computed、watch等。其中最重要的是通过Object.defineProperty来给数据设置settergetter函数,用来实现响应式依赖收集。在修改一个对象值的时候,会通过setter -> Watcher -> update的流程来修改对应的视图。

1. Object.defineProperty
/*
  obj: 目标对象
  prop:要操作的目标对象的属性名
  descriptor:{ // 描述符对象
    enumerable: Boolean 是否可枚举,默认false
    configurable: Boolean 是否可配置,默认false
    get: function getter函数,访问该属性时触发
    set:function setter函数,对属性做修改时触发
  }

  return value 传入对象
*/
Object.defineProperty(obj, prop, descriptor)
2. Observer(可观察的)

Observer类的作用就是给对象的属性添加getter和setter,用来依赖收集和派发更新。observer函数传入一个value(需要响应式化的对象)遍历所有的属性,执行Object.defineProperty处理。源码中Observer类的walk方法就是对数据进行遍历执行defineReactive方法来添加gettersetter;observeArray是将传进来的数组遍历,进行observe。

defineReactive方法中。数据的get方法执行时,如果存在当前的Watcher对象,对其进行依赖收集,并对其子对象进行依赖收集,如果是数组,则对数组进行依赖收集,如果数组的子成员还是数组,则对其遍历。执行set方法时,新的值需要observe,保证新的值是响应式的;并且dep对象会执行notify方法通知所有的Watcher观察者对象。

1. 为什么要依赖收集?

假如我们的数据data中有text,当text的值发生变化时,若视图中有用到text,那我们需要触发方法更新视图;若视图中并没有用到text,那就不需要触发更新视图的方法。而【依赖收集】会让text这个数据知道有哪些地方有依赖自己的数据,在自身发生变化的时候,需要通知他们进行更新。最终形成数据与视图的一种对应关系。

2. 依赖收集的实现

依赖收集的过程:把Watcher实例存放到对应的Dep对象中去; 依赖收集的前提:触发get方法,新建一个Watcher对象;;

1. 订阅者Dep

订阅者Dep的作用,是用来存放Watcher观察者对象。

class Dep {
  constructor () {
    /* 用来存放Watcher对象的数组 */
    this.subs = [];
  }
  /* 在subs中添加一个Watcher对象 */
  addSub (sub) {
    this.subs.push(sub);
  }
  /* 通知所有Watcher对象更新视图 */
  notify () {
    this.subs.forEach((sub) => {
      sub.update();
    })
  }
}
2. 观察者Watcher
class Watcher {
  constructor () {
    /* 在new一个Watcher对象时将该对象赋值给Dep.target, 在get中会用到 */
    Dep.target = this;
  }
  /* 更新视图方法 */
  update() {
    console.log('视图已更新)
  }
}
3. 依赖收集

使用defineReactive方法以及Vue的构造函数,完成依赖收集。在闭包中增加一个Dep类的对象,用来收集Watcher对象。在对象被【读】时,触发reactiveGetter函数将当前Watcher对象收集到Dep类中(通过存放在Dep.target);之后,当对象被【写】时,触发reactiveSetter方法通知Dep类调用notify方法通知所有Watcher对象调用update方法更新视图。在Vue的构造函数中,新建一个Watcher观察者对象,此时Dep.target便指向该对象。

Vue事件机制

1. Vue事件API

Vue.js 为我们提供了四个事件API,分别是$on, $once, $off, $emit

2. 初始化事件

Vue.js 在初始化事件时,使用initEvents方法,在vm上创建一个_events对象,用来存放事件。

export function initEvents (vm: Component) {
  /* 在vm上创建一个events对象,用来存放事件*/
  vm._events = Object.create(null)
  /* 这个标志位用来表示是否存在钩子,再不需要通过哈希表的方法来查找是否有钩子 ,减少不必要的花销,优化性能*/
  vm._hasHookEvent = false
  coonst listeners = vm.$options._parentListeners
  if (listeners) {
    updateComponentListeners(vm, listeners)
  }
}

Vue原型上添加四个方法:

  1. $on方法,用来在vm实例上监听一个自定义事件,该事件可用$emit触发。
  2. $once方法,用来在vm实例上监听一个只能触发一次的事件,在出发之后会自动移除该事件。
  3. $off方法,用来移除自定义事件。
  4. $emit方法,用来触发指定的自定义事件。

About

Vue源码理解及核心原理简单实现

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published