手机版

Vue.js每天必须学习的内部反应原理研究

时间:2021-09-07 来源:互联网 编辑:宝哥软件园 浏览:

深度响应原则

我们已经讲了大部分基本内容,现在我们来讲一下底层内容。Vue.js最显著的功能之一就是响应系统——模型只是一个普通的对象,修改它会更新视图。这使得状态管理非常简单直观,但了解其原理并避免一些常见问题也很重要。接下来,我们开始深入挖掘Vue.js响应系统的底层细节。

如何跟踪变化

将一个普通的对象作为它的数据选项传递给Vue实例,Vue.js将遍历它的属性,并将它们变成带有Object.defineProperty的getter/setter.这是ES5的一个特性,无法打补丁,这也是Vue.js不支持IE8和更早版本的原因。

用户看不到getter/setter,但在内部,他们让Vue.js跟踪依赖关系,并在属性被访问和修改时通知更改。一个问题是在浏览器控制台打印数据对象时getter/setter的格式不同,所以使用vm。$log()实例方法可以获得更友好的输出。

模板中的每个指令/数据绑定都有一个对应的观察器对象,该对象将属性记录为计算过程中的依赖项。之后,当依赖的setter被调用时,它将触发watcher重新计算,这将导致其关联的指令更新DOM。

变更检测问题

由于ES5的限制,Vue.js无法检测对象属性的增加或删除。因为Vue.js在初始化实例时会将属性转换为getter/setter,所以属性必须在数据对象上,这样Vue.js就可以转换它并使其具有响应性。例如:

var data={ a : 1 } var VM=new vue({ data : data })//` VM . a '和` data.a '现在有响应VM . b=2/` VM . b '没有响应data . b=2/` data . b '没有响应

对于Vue实例,可以使用$set(键,值)实例方法:

Vm。$set('b ',2)//`vm.b '和` data.b '现在已响应。对于普通数据对象,可以使用全局方法Vue.set(对象、键、值):

Vue.set(data,' c ',3)/` VM . c '和` data.c '现在正在响应。有时,您希望向现有对象添加一些属性,例如使用Object.assign()或_。扩展()。但是,添加到对象的新属性不会触发更新。此时,您可以创建一个新对象,包括原始对象的属性和新属性:

//不使用` object.assign (this.someobject,{a: 1,b: 2})` this.someobject=object . assign({ },this . someobject,{a: 1,b : 2 })时会出现一些与数组相关的问题

初始化数据

虽然Vue.js提供了动态添加响应属性的API,但是建议在数据对象上声明所有的响应属性。

不要这样做:

varvm=new vue({ template : ' div { { msg } }/div ' })//然后添加` msg`vm。$ set ('msg ',' hello!')这样做:

Var vm=new Vue({ data: {//用null值声明` msg`msg3360''},template 3360 ' div { { msg } }/div ' })//然后设置msg`vm.msg='Hello!'这样做有两个原因:1 .数据对象就像组件状态的模式。在其上声明所有属性使得组件代码更容易理解。

2.添加顶级响应属性将强制所有观察者重新计算,因为它以前不存在,并且没有观察者跟踪它。这样做的性能通常是可以接受的(特别是与Angular的脏检查相比),但是在初始化期间可以避免。

异步更新队列

默认情况下,Vue.js异步更新DOM。每当观察到数据变化时,Vue都会启动一个队列来缓存同一事件周期中的所有数据变化。如果观察器被触发多次,它将只被推入队列一次。在下一个事件周期之前,Vue将清空队列,只进行必要的DOM更新。在内部异步队列中,MutationObserver是首选,如果不支持,则使用setTimeout(fn,0)。

例如,如果设置了vm.someData='new value ',则不会立即更新DOM,而是在下一个事件周期清空队列时更新。我们基本上不需要关心这个过程,但是如果我们想在DOM状态更新后做一些事情,这将会有所帮助。虽然Vue.js鼓励开发人员遵循数据驱动的思想,避免直接修改DOM,但有时这样做是必要的。要在数据更改后等待Vue.js完成DOM更新,可以在数据更改后立即使用Vue.nextTick(回调)。回调在DOM更新完成后调用。例如:

div id='示例“{msg}}/div

var vm=new Vue({ el: '#example ',Data: { msg : ' 123 ' })VM . msg=' new message '/modify data VM。$ El . text content==' new message '/false vue . nexttick(function()){ VM。$ El . text content==' new message '//true })VM。$ nexttick()是一个方便的实例方法,因为它不需要全局Vue,并且它的这个回调会自动绑定到当前的Vue实例:

Vue.component('example ',{ template : ' span { { msg }}/span },data : function(){ return { msg : '未更新' } },methods : { updatemessage : function(){ this . msg=' updated ' console . log(this。$el.textContent) //='未更新'此。$ NextTick(function(){ console . log(this。$ El . text content)//=' updated ' })} } })计算属性的奥秘

您应该注意到Vue.js的计算属性不是简单的getter。计算属性跟踪其响应相关性。计算计算属性时,Vue.js会更新其依赖项列表并缓存结果。只有当其中一个依赖关系改变时,缓存的结果才是无效的。因此,只要依赖关系不变,访问计算属性将直接返回缓存结果,而不是调用getter。

为什么要缓存?假设我们有一个计算量很大的属性A,它必须遍历一个巨大的数组并进行大量计算。然后,可能还有其他依赖于A的计算属性,如果没有缓存,我们会多次调用A的getter,这是不必要的。

因为计算属性是缓存的,所以在访问它时并不总是调用getter。考虑以下示例:

var VM=new vue({ data : { msg : ' hi ' },computed : { example 3360 function(){ return date。现在()这个。msg}})对于计算属性示例只有一个依赖项:vm.msg.Date.now()不依赖于响应,因为它与Vue的数据观测系统无关。因此,当访问vm.example时,您会发现时间戳不会改变,除非vm.msg改变。

有时我希望getter不会改变它原来的行为,并在每次访问vm时调用getter。示例此时,可以为指定的计算属性关闭缓存:

computed : { example : { cache : false,get: function () {return date。now () this.msg}}}现在每次访问vm.example,时间戳都是新的。但是,只在JavaScript中访问是这样的;数据绑定仍然是依赖驱动的。如果计算属性{{example}}以这种方式绑定在模块中,则只有当响应依赖关系发生变化时,DOM才会更新。

本文已整理成《Vue.js前端组件学习教程》,欢迎大家学习阅读。

关于vue.js组件的教程,请点击专题vue.js组件学习教程学习。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:Vue.js每天必须学习的内部反应原理研究是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。