当前位置:   article > 正文

Vue-数据驱动视图(一)数据监听机制

数据驱动视图

前言

Vue的一大特点就是数据双向绑定,当数据发生变化时,也可以同时触发界面的变化,即数据驱动视图。要想实现数据驱动视图,那么有这么几个步骤:

1.收集我们需要监听的数据,并给他配置个监听器,当数据状态发生变化时触发监听器,然后判断是否需要重新渲染;

2.数据变更时重新构建虚拟DOM;

3.虚拟DOM渲染成为真实的DOM;

 

 

在这里本文主要分析其中的第一步——数据监听机制,也就是Data变化到watcher监听到的这一过程。

 

正文

一、Object的数据响应机制

Vue的数据响应主要是采用观察者模式(Observer Pattern)。所谓观察者模式,即定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在Vue中,当数据发生变化时,就会通知视图中所有和这个数据有关的地方都进行更新。

Vue首先通过定义一个Observer类,并在其内部方法中将对象所有的属性通过Object.defineProperty来添加get和set方法,从而保证所有的属性都变成了可观测的对象。

下面是具体的源码解读:

  1. //src\core\observer\index.js
  2. export class Observer {
  3. value: any;
  4. dep: Dep;
  5. vmCount: number;
  6. constructor (value: any) {
  7. this.value = value
  8. this.dep = new Dep()
  9. this.vmCount = 0
  10. def(value, '__ob__', this)
  11. if (Array.isArray(value)) {
  12. ... //当value是数组时候的处理
  13. } else {
  14. //仅当value为object的时候,调用walk去解析
  15. this.walk(value)
  16. }
  17. }
  18. /**
  19. * 遍历obj的所有属性,调用defineReactive为其添加get、set,使该属性变为可观测的
  20. */
  21. walk (obj: Object) {
  22. const keys = Object.keys(obj)
  23. for (let i = 0; i < keys.length; i++) {
  24. defineReactive(obj, keys[i])
  25. }
  26. }
  27. }

上面这段代码主要就是遍历Observer的构造函数的入参value,当为对象的时候则遍历其对象的属性,并在后续调用defineReactive方法为其添加get、set方法。defineReactive源码如下:

  1. export function defineReactive (
  2. obj: Object,
  3. key: string,
  4. val: any,
  5. customSetter?: ?Function,
  6. shallow?: boolean
  7. ) {
  8. const dep = new Dep()
  9. //如果对象属性的configurable为false时,代表该属性无法被修改,即无法为其增加get/set,直接return
  10. const property = Object.getOwnPropertyDescriptor(obj, key)
  11. if (property && property.configurable === false) {
  12. return
  13. }
  14. // cater for pre-defined getter/setters
  15. const getter = property && property.get
  16. const setter = property && property.set
  17. if ((!getter || setter) && arguments.length === 2) {
  18. val = obj[key]
  19. }
  20. //如果value是一个obj,这里会递归的处理,给value的属性添加get/set
  21. let childOb = !shallow && observe(val)
  22. //给key属性增加get/set方法
  23. Object.defineProperty(obj, key, {
  24. enumerable: true,
  25. configurable: true,
  26. get: function reactiveGetter () {
  27. const value = getter ? getter.call(obj) : val
  28. if (Dep.target) {
  29. dep.depend()
  30. if (childOb) {
  31. childOb.dep.depend()
  32. if (Array.isArray(value)) {
  33. dependArray(value)
  34. }
  35. }
  36. }
  37. return value
  38. },
  39. set: function reactiveSetter (newVal) {
  40. const value = getter ? getter.call(obj) : val
  41. /* eslint-disable no-self-compare */
  42. if (newVal === value || (newVal !== newVal && value !== value)) {
  43. return
  44. }
  45. /* eslint-enable no-self-compare */
  46. if (process.env.NODE_ENV !== 'production' && customSetter) {
  47. customSetter()
  48. }
  49. // #7981: for accessor properties without setter
  50. if (getter && !setter) return
  51. if (setter) {
  52. setter.call(obj, newVal)
  53. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/283852?site
推荐阅读
相关标签
  

闽ICP备14008679号