MVVM与Vue响应式的实现
创始人
2024-03-17 22:50:05
0

Vue的响应式实现原理

MVVM

M:模型 ==》data中的数据

V:视图 ==》模板

VM:视图模型 ==》Vue实例对象

在这里插入图片描述

ViewModel是一个中间的桥梁将视图View与模型Model连接起来,ViewModel内部通过数据绑定,实现数据变化,视图发生更新变化,通过数据劫持实现的数据绑定;通过dom监听,实现事件触发,调用对应的回调函数,比如更新数据(数据变化了,视图就会更新–数据绑定)

Vue 的设计也受到了MVVM的启发,View对应的是dom,它的ViewModel对应的式Vue实例,,Model对应的是data对象;通过数据劫持来实现数据绑定;编译(事件指令)的时候添加事件监听

Vue的响应式原理

主要是:数据代理、数据绑定、模板编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iKZWJxqy-1670162086242)(C:\Users\lucas\Desktop\学习\图片\reactive.jpg)]

绿线是初始化时执行的,红线是数据更新时触发的

一、初始化的时候:

1》数据代理

数据代理就是通过一个对象代理对另一个对象中属性的操作(读/写);vue中通过vm代理data对象(vm代理vm._data)中所有属性的操作,更方便的操作data中的数据

vue中数据代理:将vue文件中的data保存一份到vm._data; 然后对将vue文件中data中的每个属性添加到vm实例上,通过Object.defineProperty实现数据的代理;当我们读取vm上的属性时,他会到vm._data中找到对应的属性返回当,我们修改vue实例对象的属性后,对应的setter就会监听到变化,然后去修改实例对象上vm._data对应的属性

    Object.defineProperty(me, key, {configurable: false, // 不可以重新定义enumerable: true, // 可枚举遍历// 当执行vm.name获取属性值时自动调用返回属性值get: function proxyGetter() {// 读取data中对应的属性值返回return me._data[key];},// 当执行vm.name = "xxx"时自动调用set: function proxySetter(newVal) {// 将最新的值保存给data对应的属性上me._data[key] = newVal;}});

2》数据绑定:

数据绑定

初始化显示:页面(表达式、指令)能从data读取数据希纳是(编译、解析)

更新显示:更新data中的属性数据,能够更新页面

数据劫持

1》数据劫持是vue实现数据绑定的一种技术

2》基本思想:通过defineProperty()来监视data中所有属性(任意层次)数据的变化,一旦变化就更新界面

具体实现:

采用递归的方式为data中的每个层级的属性创建dep(实例对象),并通过defineProperty对data进行重新定义,实现数据劫持;在set中判断数据是否发生了变化,如果发生改变,一方面他会更新值,新的值是需要重新劫持监听;另一方面会通知所有相关订阅者watcher去更新界面;在get中不仅返回值,还需要建立watcher与dep的关系(这个get会在模板解析大括号表达式和指令时触发);给Watcher添加Dep,给watch的subs中push对应dep

dep对象:

{
id;0,
subs:[]
}

dep的id从0开始递增,每个属性对应一个dep,劫持

watcher对象:

{vm:MVVMexp:"name",depIds:{depId:dep}  // depId就是上面dep的id,是个数字cb: textUpdater,value:"luca"
}

watcher与dep的关系

多对多的关系

一个dep可能对应多个watcher; eg:一个属性在多个标签中使用

一个watcher可能的对应多个dep; eg: {{a.b.c}}

什么时候建立关系:编译、解析模板(大括号表达式和非事件指令)时建立

怎么建立关系:创建watcher时会读取data中的值,defineProperty中get会建立双方关系;在dep的subs中push了watcher,且在watcher的depIds中添加了对应dep

劫持的部分代码:

  defineReactive: function (data, key, val) {// 创建对应的dep对象var dep = new Dep();// 通过隐式递归调用, 实现对所有层次属性的劫持var childObj = observe(val);// 给data中指定属性进行重新定义Object.defineProperty(data, key, {enumerable: true, // 可枚举configurable: false, // 不能再define// 返回属性值, 同建立dep与watcher之间的关系get: function () {if (Dep.target) {dep.depend();}return val;},// 监视属性值的变化, 一旦变化去更新对应的界面set: function (newVal) {if (newVal === val) {return;}val = newVal;// 是object的新的值话,进行监听childObj = observe(newVal);// 通知订阅者dep.notify();},});},

3》编译模板

1、将el所有的子节点去除,添加到加到一个新建的文档 fragment 对象中

2、对 fragment中所有层次子节点递归进行编译解析处理

编译大括号表达式和一般指令时创建watcher;创建watcher时指定了更新函数(因为要更新的可能是a.b.c这种,所以要遍历,取值是从_data中取的);这是初始化需要读取_data中的数据,就会走对应属性的get,从而建立dep与watcher的关系,给dep的subs中push了对应的watcher,并且在watcher中的depIds添加了对应的dep

1》对表达式文本进行解析

​ a、根据正则对象匹配的表达式字符串( 匹配eg:{{obj.age}} ):子匹配

​ b、将属性值设置为文本节点的 textContent

​ c、从data中去除表达式对应的属性(通过.来分割成数组后遍历,因为可能由多层 a.b.c)

2》对元素节点的指令属性进行解析

a》 事件指令的解析

​ a.1、从指令中取出事件名

​ a2、根据指令的值从methods中得到对应的事件处理函数对象

​ a3、给当前元素节点绑定事件名和事件回调函数的事件监听

​ a4、指令解析完成后,移除次指令属性

b》一般指令的解析

​ b.1、从表达式中取出指令名和指令值

​ b.2、从data中根据表达式得到对应的值

​ b.3、根据指令名确定需要操作的元素节点的什么属性

​ b.4 、将表达式的值设置到对应的属性上(v-text:textContent;;v-html:innerHtml; v-class :className)

​ b5、移除元素的指令属性

3、将解析后的 fragment 添加到el中显示

fragment修改并不会引起页面的更新

二、数据变化的时候

监听到_data的变化,set首先判断值有没有变化,发生变化而且是个对象的话会重新调用observe函数进行监听;通知所有相关的订阅者更新界面(通过遍历subs,调用watcher中的回调函数函数来更新界面)

双向数据绑定的实现

双向绑定是建立在单项数据绑定的基础上;只是在解析v-model指令时,给当前元素添加了input监听;当input的value发生改变时,修改对应的_data中的属性

v-model 是动态属性绑定 v-bind 与 input事件的语法糖

关的订阅者更新界面(通过遍历subs,调用watcher中的回调函数函数来更新界面)

双向数据绑定的实现

双向绑定是建立在单项数据绑定的基础上;只是在解析v-model指令时,给当前元素添加了input监听;当input的value发生改变时,修改对应的_data中的属性

v-model 是动态属性绑定 v-bind 与 input事件的语法糖

相关内容

热门资讯

广东建工:公司与广州地铁不存在... 证券之星消息,广东建工(002060)12月25日在投资者关系平台上答复投资者关心的问题。 投资者提...
“政策找人”暖民心 服务下沉“... 城乡居民基本医疗保险作为我国覆盖人群最多的基本医疗保险,是基本医疗保障体系中的重要一环。为切实维护人...
我市举办调解工作专题培训 为深入贯彻法治政府建设要求,全面提升基层矛盾纠纷化解能力,12月19日,市司法局牵头举办了全市调解工...
河南将优化涉企法律服务,营造法... 【大河财立方 记者 朱娟 见习记者 岳炎霖】12月26日,大河财立方记者在省政府新闻办召开的《河南省...
新版河南省优化营商环境条例哪些... 【大河财立方 记者 朱娟 见习记者 岳炎霖】12月26日,河南省政府新闻办召开《河南省优化营商环境条...
原创 中... 12月25日,家纺企业富安娜披露了关于中信证券固定收益类理财产品逾期兑付的进展公告。公告显示,公司近...
封关临近!海南自贸港政策红利释... 交易所数据显示,2025年12月26日09时47分,京粮控股当前价格为8.92元,涨幅为9.99%,...
字节跳动通报:120名员工被辞... 12月25日,字节跳动披露2025年三季度内部违规案例的处理情况。通报显示,三季度共有120名员工因...
上亿理财难收回,家纺龙头富安娜... 12月25日晚,家纺龙头企业深圳市富安娜家居用品股份有限公司(以下简称富安娜,002327.SZ)发...
华院计算取得法律要素图谱辅助类... 国家知识产权局信息显示,华院计算技术(上海)股份有限公司取得一项名为“一种法律要素图谱辅助类案推荐方...