Vue双向数据绑定原理-下

Vue双向数据绑定原理-下这一篇文章主要讲解Vue双向数据绑定的原理,主要是通过Object.defineProperty()来实现的,这里我们手写Vue双向数据绑定的原理。

首先我提出一个需求,我的需求是,快速监听对象中所有属性的变化

首先得要有一个对象,对象的定义代码如下:

<script>
    let obj = {
        name: 'BNTang',
        age: 33
    };
</script>

然后我们需要监听这个对象中所有属性的变化,最最最简单的做法如下,这里我们可以使用Object.defineProperty()来实现,代码如下:

Object.defineProperty(obj, 'name', {
    get() {
        return 'BNTang';
    },
    set(newValue) {
    }
});

Object.defineProperty(obj, 'age', {
    get() {
        return 18;
    },
    set(newValue) {
    }
});

这样我们就可以监听到对象中所有属性的变化了,但是这样写的话,代码量太大了,如果有100个属性,那么就要写100次,这样的话,代码量太大了,所以我们需要写一个函数来实现这个功能(例如自定义类)。

博主这里采用的是自定义类的方式来实现,首先定义一个类,代码如下:

class Observer {
    
}

只要将需要监听的那个对象传递给Observer这个类,这个类就可以快速的给传入的对象的所有属性都添加get/set方法, 该类的主要功能就是给传入的对象的所有属性都添加get/set方法。

首先我定义了一个构造函数,绑定了一个形参,就是需要监听的对象,代码如下:

constructor(data) {
}

在然后我定义了一个 observer 方法,将需要监听的对象传递给 observer 方法,遍历取出传入对象的所有属性,给遍历到的属性都增加get/set方法,代码如下:

observer(obj) {
    if (obj && typeof obj === 'object') {
        for (let key in obj) {
        }
    }
}

在 for 循环中,我使用了 defineReactive 方法(自定义一个方法单独来处理),该方法的作用是给传入的对象的所有属性都添加get/set方法,代码如下:

defineReactive(obj, attr, value) {
    Object.defineProperty(obj, attr, {
        get() {
            return value;
        },
        set: (newValue) => {
            if (value !== newValue) {
                value = newValue;
                console.log('监听到数据的变化, 需要去更新UI');
            }
        }
    })
}

好了,现在我们已经定义了一个类,该类的主要功能就是给传入的对象的所有属性都添加get/set方法,那么我们就可以使用这个类了(Test 阶段),代码如下:

new Observer(obj);
obj.name = 'Example';

image-20230930210837470

查看打印结果,可以看到,我们已经监听到了数据的变化,但是这里有一个问题,就是我们只能监听到对象中已经存在的属性的变化,不能监听对象中属性的对象的属性的变化,例如下面的对象代码:

let obj = {
    name: {a: 'abc'},
    age: 33
};

就是对象中的属性值又是一个对象,而这个属性的对象的属性值发生改变,我们自定义的 Observer 是无法进行监听到的。所以我们需要对这个问题进行处理(如果属性的取值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法)。

this.observer(value);

image-20230930211954721

测试一下:

obj.name.a = 'Example';

image-20230930212158329

可以看到,我们已经可以监听到对象中属性的对象的属性值的变化了。

但是这里还有一个问题,就是如果对象中的属性值是一个基本数据类型,我们在给这个对象绑定完毕get/set方法之后,再给这个对象赋值的时候, 赋值成了引用类型, 新赋值的属性的对象的值是不会被监听到的。例如下面的代码:

<script>
    let obj = {
        name: 'BNTang',
        age: 33
    };

    class Observer {
        constructor(data) {
            this.observer(data);
        }

        observer(obj) {
            if (obj && typeof obj === 'object') {
                for (let key in obj) {
                    this.defineReactive(obj, key, obj[key]);
                }
            }
        }

        defineReactive(obj, attr, value) {
            this.observer(value);
            Object.defineProperty(obj, attr, {
                get() {
                    return value;
                },
                set: (newValue) => {
                    if (value !== newValue) {
                        value = newValue;
                        console.log('监听到数据的变化, 需要去更新UI');
                    }
                }
            })
        }
    }

    new Observer(obj);
    obj.name = {a: 'abc'};
    obj.name.a = 'BNTang';
</script>

运行结果:

image-20231002100147828

可以看到,只能监听到对象属性值初始化的时候的变化,不能监听到对象属性值重新赋值的为对象的属性值的变化。

所以我们需要对这个问题进行处理,我们需要在给对象属性值重新赋值的时候,给这个对象属性值重新绑定get/set方法(如果给属性赋值的新值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法),代码如下:

image-20231002100634235

运行结果:

image-20231002100655409

posted @   BNTang  阅读(78)  评论(0编辑  收藏  举报
  1. 1 总会有人离开 王巨星
  2. 2 月亮 孟凡明
  3. 3 迟里乌布
  4. 4 我只能离开 颜人中
  5. 5 达尔文 蔡健雅
  6. 6 夜色滚烫 叶明净
  7. 7 你的星环 路飞文
  8. 8 不再说话 三块木头
  9. 9 黄昏 粥粥和小伙/粥粥
  10. 10 爱不单行 刘大拿
  11. 11 心动贩卖机 PIggy
  12. 12 别来无恙 苏星婕
  13. 13 我们的歌 刘大拿
  14. 14 一直很安静 王贰浪
  15. 15 去有风的地方 清音
  16. 16 雪 Distance Capper/罗言
  17. 17 坏女孩 徐良/小凌
  18. 18 乐园 沧桑Cang333/虎皮蛋/曲甲
  19. 19 Ayo(Explicit) Chris Brown/Tyga
  20. 20 我的美丽feat.海洋Bo 海洋Bo/高睿
  21. 21 世事可爱 粥粥和小伙/粥粥
  22. 22 我记得 赵雷
  23. 23 我想牵着你的手 许嵩
  24. 24 人们都不懂 刘诺然
  25. 25 寻一个你(电视剧《苍兰诀》温情主题曲) TTTTTeehom
  26. 26 子莫格尼 杉和
  27. 27 Cat Cafe Shoffy
  28. 28 风停了雨停了我们还拥抱着 Superluckyqi
  29. 29 寂寞沙洲冷 于潼
  30. 30 三国恋 王巨星
  31. 31 达尔文 林俊杰
  32. 32 有些 颜人中
  33. 33 小模样 张小只ya
  34. 34 是否 程响
  35. 35 楼顶上的小斑鸠 队长
  36. 36 笑场 薛之谦
  37. 37 还是分开 张叶蕾
  38. 38 修炼爱情 林俊杰
  39. 39 二零三 毛不易
  40. 40 雅俗共赏 许嵩
  41. 41 Serendipity 古瑞斯Graps/Zakiya晴子
  42. 42 就让这大雨全都落下·2023 刘大拿
  43. 43 老男孩 筷子兄弟
  44. 44 有何不可 许嵩
  45. 45 缓缓 杜宣达
  46. 46 好久不见 陈奕迅
  47. 47 爱的魔法(Cover 金莎) 封茗囧菌
  48. 48 在你的身边 盛哲
  49. 49 带我去找夜生活 告五人
  50. 50 假面舞会 很美味
  51. 51 STAY The Kid LAROI/Justin Bieber
  52. 52 我好想睡觉的 无敌西红柿
  53. 53 日不落(温柔版)
  54. 54 恋爱画板 锦零
  55. 55 7710 好乐无荒/尹露浠
  56. 56 给你呀(又名:for ya) 蒋小呢
  57. 57 Love Story Taylor Swift
  58. 58 Plain Jane(Remix 13z) 鱼幼微
  59. 59 晚风 7opy/BT07
  60. 60 拜托 孙晨
  61. 61 乌梅子酱 李荣浩
  62. 62 南半球与北海道 范倪Liu
  63. 63 星河万里 Rom邢锐
乐园 - 沧桑Cang333/虎皮蛋/曲甲
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

Loading

点击右上角即可分享
微信分享提示