赞
踩
Vue的一大特点就是数据双向绑定,当数据发生变化时,也可以同时触发界面的变化,即数据驱动视图。要想实现数据驱动视图,那么有这么几个步骤:
1.收集我们需要监听的数据,并给他配置个监听器,当数据状态发生变化时触发监听器,然后判断是否需要重新渲染;
2.数据变更时重新构建虚拟DOM;
3.虚拟DOM渲染成为真实的DOM;
在这里本文主要分析其中的第一步——数据监听机制,也就是Data变化到watcher监听到的这一过程。
Vue的数据响应主要是采用观察者模式(Observer Pattern)。所谓观察者模式,即定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在Vue中,当数据发生变化时,就会通知视图中所有和这个数据有关的地方都进行更新。
Vue首先通过定义一个Observer类,并在其内部方法中将对象所有的属性通过Object.defineProperty来添加get和set方法,从而保证所有的属性都变成了可观测的对象。
下面是具体的源码解读:
- //src\core\observer\index.js
- export class Observer {
- value: any;
- dep: Dep;
- vmCount: number;
-
- constructor (value: any) {
- this.value = value
- this.dep = new Dep()
- this.vmCount = 0
- def(value, '__ob__', this)
- if (Array.isArray(value)) {
- ... //当value是数组时候的处理
- } else {
- //仅当value为object的时候,调用walk去解析
- this.walk(value)
- }
- }
-
- /**
- * 遍历obj的所有属性,调用defineReactive为其添加get、set,使该属性变为可观测的
- */
- walk (obj: Object) {
- const keys = Object.keys(obj)
- for (let i = 0; i < keys.length; i++) {
- defineReactive(obj, keys[i])
- }
- }
- }
上面这段代码主要就是遍历Observer的构造函数的入参value,当为对象的时候则遍历其对象的属性,并在后续调用defineReactive方法为其添加get、set方法。defineReactive源码如下:
- export function defineReactive (
- obj: Object,
- key: string,
- val: any,
- customSetter?: ?Function,
- shallow?: boolean
- ) {
- const dep = new Dep()
- //如果对象属性的configurable为false时,代表该属性无法被修改,即无法为其增加get/set,直接return
- const property = Object.getOwnPropertyDescriptor(obj, key)
- if (property && property.configurable === false) {
- return
- }
-
- // cater for pre-defined getter/setters
- const getter = property && property.get
- const setter = property && property.set
- if ((!getter || setter) && arguments.length === 2) {
- val = obj[key]
- }
- //如果value是一个obj,这里会递归的处理,给value的属性添加get/set
- let childOb = !shallow && observe(val)
- //给key属性增加get/set方法
- Object.defineProperty(obj, key, {
- enumerable: true,
- configurable: true,
- get: function reactiveGetter () {
- const value = getter ? getter.call(obj) : val
- if (Dep.target) {
- dep.depend()
- if (childOb) {
- childOb.dep.depend()
- if (Array.isArray(value)) {
- dependArray(value)
- }
- }
- }
- return value
- },
- set: function reactiveSetter (newVal) {
- const value = getter ? getter.call(obj) : val
- /* eslint-disable no-self-compare */
- if (newVal === value || (newVal !== newVal && value !== value)) {
- return
- }
- /* eslint-enable no-self-compare */
- if (process.env.NODE_ENV !== 'production' && customSetter) {
- customSetter()
- }
- // #7981: for accessor properties without setter
- if (getter && !setter) return
- if (setter) {
- setter.call(obj, newVal)
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。