当前位置: 首页 > Web前端 > vue.js

[vue]MVVM,双向绑定

时间:2023-03-31 19:10:38 vue.js

MV*模式MVCMVPMVVM1一个MVC应用分为三部分Model(模型):数据存储应用数据,控制和修改这些数据的业务规则WhenModelchanges:notifyView,forView提供了查询Model相关状态的能力,并为Controller提供了访问封装在Model内部的应用功能的能力。视图(View):用户界面组织了Model的内容。当Model发生变化时:View负责维护数据表示的一致性,View将用户的请求通知给Controller。控制器(Controller):业务逻辑应用的行为解释来自View的用户请求,将请求映射到行为,然后通过Model实现这些行为。结构图:View将指令传递给ControllerController完成业务逻辑并要求Model改变状态Model将新数据发送给View,用户通过View接受指令并传递给ControllerController直接接受指令得到反馈并接受指令2MVP模型(Model):提供数据视图(View):用户界面展示者(Presenter):逻辑处理结构图View与Model没有联系,通过Presenter传递。View-passive视图中没有部署业务逻辑。所有逻辑都部署在Presenter和MVC中区别在于View不能直接从Model3读取数据MVVM与MVP模式基本一致模型(Model):保存数据视图(View):用户界面数据驱动(View-Model):业务逻辑VM负责转换Model中的数据对象,当结构图操作View时,ViewModel感知到变化,并通知Model相应的变化。如果Model发生变化,ViewModel会感知到变化并通知View更新ViewModel和View之间的双向数据绑定。Model通过接口请求数据交互,承上启下。双向数据绑定Vue2:Object.defineProperty()Vue3:Proxy代理1Vue2双向绑定实现Object.defineProperty(obj,prop,description)原理,无需依赖收集/***执行Object.defineProperty()Encapsulation*/functiondefineReactive(obj,key,value){//递归——对象的属性仍然是对象observe(value);//变化检测Object.defineProperty(obj,key,{get(){returnvalue;},set(newVal){if(newVal!==value){updateView();value=newVal;observe(newVal)}}})}/***对一个对象所有属性的变化检测*/functionobserve(target){//非对象,直接返回if(typeoftarget!=='object'){returntarget;}//将每个属性转换成getter和setter形式for(letkeyintarget){defineReactive(target,key,target[key])}}//模拟更新视图函数的方法updateView(){console.log("Updatetheview");}通过直接调用observe来检测对象属性的变化,在对象上存在性能不佳的问题无法检测到新属性无法检测到更改数组的长度属性2Vue3二-绑定方式实现Proxy是一个wrapper,可以拦截和改变底层JavaScript引擎的操作,性能更好Arrays可以触发get和setlikeobjects[js]代理和反射(Proxy/Reflect)[阮一峰】ES6标准-简析Proxy原理,不依赖采集的基本过程cosnto={name:"张三"}constproxy=newProxy(o,{get(target,key,receiver){console.log("读取获取属性值")},set(target,key,value,receiver){console.log("设置属性值")},deleteProperty(target,key){console.log("删除属性")}})代理.name;//读取属性值proxy.name="Lisi";//设置属性值deleteproxy[name];//删除属性的自定义业务逻辑//判断是否为对象functionisObj(val){returnval!==null&&typeofval==="object"}//判断当前对象是否有指定属性functionhasOwn(target,key){returntarget.hasOwnProperty(key)}//存储代理信息consttoProxy=newWeakMap()consttoRaw=newWeakMap()/***创建响应式对象*/functioncreateReactiveObj(target){//target不是对象,直接返回targetif(!isObj(target)){returntarget}constproxy=toProxy.get(target)//如果目标对象已经被代理,直接返回代理对象if(proxy){returnproxy}//如果目标对象是代理对象,并且有对应的真实对象,直接returnif(toRaw.has(target)){returntarget}//生成代理对象constobserved=newProxy(target,{get(target,key,receiver){console.log("读取值");constresult=Reflect.get(target,key,receiver)//为返回值添加代理returnisObj(result)?reactive(result):result},set(target,key,value,receiver){//判断目标对象中是否已经存在该属性consthasProperty=hasOwn(target,key)constoldVal=Reflect.get(target,key)if(!hasProperty){console.log("添加属性");}elseif(oldVal!==value){console.log("修改属性");}returnReflect.set(target,key,value,receiver)},deleteProperty(target,key){console.log("删除值");returnReflect.deleteProperty(target,key)}})//将目标对象和代理对象添加到Map中toProxy.set(target,observed)toRaw.set(observed,target)returnobserved}//响应式入口函数reactive(target){returncreateReactiveObj(target)}自定义实现的函数相比基本流程,解决了多层物体检测问题,get中的判断使用WeakMap为多个代理存储代理信息,判断是否被代理,如果是代理对象数组push,有两次get,一次属性,一次新旧值比较长度。push元素后,长度变了,第二次get错误。对长度的任何修改都会避免添加值,并且视图会更新两次。Proxyhandler中可以写很多方法来满足复杂的业务需求