ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Vue响应式原理

2021-04-19 18:03:08  阅读:232  来源: 互联网

标签:Vue Presenter vm 响应 原理 Model property View


官网链接:https://cn.vuejs.org/v2/guide/reactivity.html   了解vue双向绑定原理之前,先了解一下 MV* 模式 笔记来源:http://www.linuxidc.com/Linux/2015-10/124622.htm 一、MV*

MVC

用户的对View操作以后,View捕获到这个操作,会把处理的权利交移给Controller(Pass calls);Controller接着会执行相关的业务逻辑, 这些业务逻辑可能需要对Model进行相应的操作;当Model变更了以后,会通过观察者模式(Observer Pattern)通知View; View通过观察者模式收到Model变更的消息以后,会向Model请求最新的数据,然后重新更新界面。    
  1. View是把控制权交移给Controller,自己不执行业务逻辑。
  2. Controller执行业务逻辑并且操作Model,但不会直接操作View,可以说它是对View无知的。
  3. View和Model的同步消息是通过观察者模式进行,而同步操作是由View自己请求Model的数据然后对视图进行更新。
  特别注意的是MVC模式的精髓在于第三点:     Model的更新是通过观察者模式告知View的,具体表现形式可以是Pub/Sub或者是触发Events。而网上很多对于MVC的描述都没有强调这一点。 通过观察者模式的好处就是:不同的MVC三角关系可能会有共同的Model,一个MVC三角中的Controller操作了Model以后,两个MVC三角的View都会接受到通知,然后更新自己。 保持了依赖同一块Model的不同View显示数据的实时性和准确性。  

MVC的优缺点

优点:
  1. 把业务逻辑全部分离到Controller中,模块化程度高。当业务逻辑变更的时候,不需要变更View和Model,只需要Controller换成另外一个Controller就行了(Swappable Controller)。
  2. 观察者模式可以做到多视图同时更新。
缺点:
  1. Controller测试困难。因为视图同步操作是由View自己执行,而View只能在有UI的环境下运行。在没有UI环境下对Controller进行单元测试的时候,Controller业务逻辑的正确性是无法验证的:Controller更新Model的时候,无法对View的更新操作进行断言。
  2. View无法组件化。View是强依赖特定的Model的,如果需要把这个View抽出来作为一个另外一个应用程序可复用的组件就困难了。因为不同程序的的Domain Model是不一样的
  MVP 和MVC模式一样,用户对View的操作都会从View交移给Presenter。Presenter同样的会执行相应的业务逻辑,并且对Model进行相应的操作; 而这时候Model也是通过观察者模式把自己变更的消息传递出去,但是是传给Presenter而不是View。 Presenter获取到Model变更的消息以后,通过View提供的接口更新界面。
  1. View不再负责同步的逻辑,而是由Presenter负责。Presenter中既有业务逻辑也有同步逻辑。
  2. View需要提供操作界面的接口给Presenter进行调用。(关键)
  优点:
  1. 便于测试。Presenter对View是通过接口进行,在对Presenter进行不依赖UI环境的单元测试的时候。可以通过Mock一个View对象,这个对象只需要实现了View的接口即可。然后依赖注入到Presenter中,单元测试的时候就可以完整的测试Presenter业务逻辑的正确性。这里根据上面的例子给出了Presenter的单元测试样例
  2. View可以进行组件化。在MVP当中,View不依赖Model。这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务逻辑完全无知。它只需要提供一系列接口提供给上层操作。这样就可以做到高度可复用的View组件。
缺点:
  1. Presenter中除了业务逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑,造成Presenter比较笨重,维护起来比较困难。
    MVVM MVVM的调用关系和MVP一样。但是,在ViewModel当中会有一个叫Binder,或者是Data-binding engine的东西。 以前全部由Presenter负责的View和Model之间数据同步操作交由给Binder处理。你只需要在View的模版语法当中,指令式地声明View上的显示的内容是和Model的哪一块数据绑定的。 当ViewModel对进行Model更新的时候,Binder会自动把数据更新到View上去,当用户对View进行操作(例如表单输入),Binder也会自动把数据更新到Model上去。 这种方式称为:Two-way data-binding,双向数据绑定。可以简单而不恰当地理解为一个模版引擎,但是会根据数据变更实时渲染。 优点:
  1. 提高可维护性。解决了MVP大量的手动View和Model同步的问题,提供双向绑定机制。提高了代码的可维护性。
  2. 简化测试。因为同步逻辑是交由Binder做的,View跟着Model同时变更,所以只需要保证Model的正确性,View就正确。大大减少了对View同步更新的测试。
缺点:
  1. 过于简单的图形界面不适用,或说牛刀杀鸡。
  2. 对于大型的图形应用程序,视图状态较多,ViewModel的构建和维护的成本都会比较高。
  3. 数据绑定的声明是指令式地写在View的模版当中的,这些内容是没办法去打断点debug的。
  二、追踪变化 现在是时候深入一下了!Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。   当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。 这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。 问题1: 由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。 Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化, 所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如: var vm = new Vue({   data:{     a:1   } })   // `vm.a` 是响应式的   vm.b = 2   // `vm.b` 是非响应式的 对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是, 对于对象 可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如,对于: Vue.set(vm.someObject, 'b', 2)   还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名: this.$set(this.someObject,'b',2)   有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。 // 代替 `Object.assign(this.someObject, { a: 1, b: 2 })` this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })   对于数组 Vue 不能检测以下数组的变动:
  1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength
var vm = new Vue({   data: {     items: ['a', 'b', 'c']   } }) vm.items[1] = 'x' // 不是响应性的 vm.items.length = 2 // 不是响应性的   解决方法 Vue.set(vm.items, indexOfItem, newValue) vm.$set(vm.items, indexOfItem, newValue) // Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue)   由于 Vue 不允许动态添加根级响应式 property,所以你必须在初始化实例前声明所有根级响应式 property,哪怕只是一个空值: var vm = new Vue({   data: {     // 声明 message 为一个空值字符串     message: ''   },   template: '<div>{{ message }}</div>' }) // 之后设置 `message` vm.message = 'Hello!'   如果你未在 data 选项中声明 message,Vue 将警告你渲染函数正在试图访问不存在的 property。   异步更新队列 Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。   例如,当你设置 vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。   Object.defineProperty的大致实现如: <body>     <div id="box">       </div>     <script>         var obox = document.getElementById("box")         var obj = {}         // obj.name ="kerwin"         Object.defineProperty(obj,"myname",{             get(){                 console.log("被访问")             },             set(data){                 console.log("被修改",data)                 obox.innerHTML = data             }         })     </script> </body>  

注意:vue3 的 变化

Object.defineProperty有以下缺点。 1、无法监听es6的Set、Map 变化; 2、无法监听Class类型的数据; 3、属性的新加或者删除也无法监听; 4、数组元素的增加和删除也无法监听。 针对Object.defineProperty的缺点,ES6 Proxy都能够完美得解决,它唯一的缺 点就是,对IE不友好,所以vue3在检测到如果是使用IE的情况下(没错,IE11都不 支持Proxy),会自动降级为Object.defineProperty的数据监听系统。

标签:Vue,Presenter,vm,响应,原理,Model,property,View
来源: https://www.cnblogs.com/wuziqiang/p/14677928.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有