Vue.js实现数据响应的方法
很多前端JavaScript框架(比如Angular、React、Vue)都有自己的数据对应引擎。通过理解对应关系及其工作原理,您可以提高开发技能并更有效地使用JavaScript框架。在视频和下面的文章中,我们构建了与您在Vue源代码中看到的相同类型的反应性。
如果你看这个视频而不是看一篇文章,请观看系列的下一个视频,并与Vue的创始人尤雨溪讨论反应和代理。
反应性系统
当你第一次看到它时,Vue的反应系统看起来很神奇。以这个简单的Vue应用程序为例:
不知何故,Vue只知道如果价格发生变化,它应该做三件事:
更新我们网站上的价格值。重新计算表达式乘以价格*数量并更新页面。再次调用totalPriceWithTax函数并更新页面。但是等等,你应该会很惊讶,当价格变化的时候,Vue怎么知道更新什么,怎么跟踪一切?
这不是JavaScript编程的正常工作方式。
如果你不明白,让我们试着看看普通的JavaScript是如何工作的。例如,如果我运行以下代码:
你觉得它能印出什么?因为我们不用Vue,它会打印10张。
在Vue,我们希望每当价格或数量更新时,总数都会更新。我们希望:
不幸的是,JavaScript是程序性的,而不是被动的,所以在现实生活中不起作用。为了使数据发生相应的变化,我们必须使用JavaScript使事情的行为有所不同。
问题
我们需要保存计算总数的方法,以便在价格或数量发生变化时可以重新运行。
解决办法
首先,我们需要一些方法来告诉我们的应用程序,“我将运行代码,存储它,我可能需要您在另一个时间运行它。”然后我们将运行代码,如果价格或数量变量被更新,再次运行存储的代码。
请注意,我们在目标变量中存储了一个匿名函数,然后调用了一个记录函数。我也可以使用ES6箭头语法来写这个:
请注意,我们在目标变量中存储了一个匿名函数,然后调用了一个记录函数。我也可以使用ES6箭头语法来写这个:
记录方法:
我们正在存储目标(在我们的示例中,{total=price * quantity}),因此我们可以稍后运行它。
这将遍历存储在存储阵列中的所有匿名函数,并执行每个函数。
然后在我们的代码中,我们可以:
是不是很简单?如果您需要阅读它并尝试再次掌握它,这里的代码是完整的。仅供参考,如果你想知道原因,我会用具体的方式编码。
问题
我们可以根据需要继续记录目标,但是有一个更强大的解决方案可以扩展我们的应用程序。这是一个负责维护目标列表的类,当我们需要它们再次运行时,它会被通知。
变通方法:使用类
我们可以开始解决这个问题的一种方法是将这个行为封装到它自己的class中,Class是一个实现标准编程观察器模式的依赖类。
因此,如果我们创建一个JavaScript类来管理我们的依赖关系(这更接近Vue处理事情的方式),它可能如下所示:
让它运行:
它仍然有效,现在我们的代码感觉更可靠了。唯一还觉得有点奇怪的是target()的设置和运行。
问题
我们将为每个变量设置一个Dep类,并很好地封装创建需要监控更新的匿名函数的行为。也许观察者的功能可能是处理这种行为。
(这只是上面的代码)
我们可以将其更改为:
解决方案:观察者功能
在我们的Watcher函数中,我们可以做一些简单的事情:
如您所见,watcher函数接受myFunc参数,将其设置为我们的全局目标属性,调用dep.depend()将目标添加为订阅者,调用目标函数并重置目标。
现在,当我们运行以下内容时:
你可能想知道为什么我们将target实现为一个全局变量,而不是将其传递给我们需要的函数。这有一个很好的理由,这将在我们文章的最后揭示。
问题
我们有一个Dep类,但是我们真正想要的是每个变量都有自己的Dep。在我们继续之前,存储数据。
让我们假设我们的每个属性(价格和数量)都有自己的内部Dep类。
当我们奔跑时:
访问了data.price值后,我希望price属性的Dep类将我们的匿名函数(存储在目标中)推送到它的订户数组(通过调用dep.depend())。我还希望quantity属性的Dep类将这个匿名函数(存储在目标中)推送到它的订阅者数组,因为我已经访问了data.quantity
如果我有另一个只访问数据. price的匿名函数,我只想把它推送到price属性的Dep类。
我想什么时候打电话给价格订阅者的dep.notify()。定价的时候想给他们打电话。在文章的最后,我希望能够进入控制台并执行:
我们需要一些方法来挂钩数据属性(如价格或数量),这样我们就可以在访问目标时将其保存到我们的订阅者数组中,并在更改时运行存储在我们的订阅者数组中的函数。
解决方案:对象。定义属性()
我们需要理解Object.defineProperty()函数,它是一个简单的ES5 JavaScript。它允许我们为属性定义getter和setter函数。在我展示如何在Dep类中使用它之前,让我展示如何使用修改后的函数。
如你所见,它只记录了两行。然而,它实际上并没有获取或设置任何值,因为我们过度使用了这个函数。我们现在把它加回去。Get()需要返回值,而set()仍然需要更新一个值,所以让我们添加一个internalValue变量来存储我们当前的价格值。
既然我们的get和set正常工作,你认为会打印到控制台上什么?
因此,当我们获取并设置值时,我们可以得到通知。通过一些递归,我们可以对数组中的所有项目运行它
仅供参考,对象键(数据)返回一个对象键数组。
现在一切都有了getter和setter,我们在控制台上可以看到。
将两种想法结合起来
当这样的一段代码运行并得到价格的值时,我们希望价格记住这个匿名函数(target)。因此,如果价格改变或设置为新值,它将触发该函数再次运行,因为它知道该行依赖于它。所以你可以这样想。
Get=记住这个匿名函数,当我们的值改变时,我们将再次运行它。
Set=运行保存的匿名函数,我们的值刚刚改变。
或者就我们副班而言
获取价格=调用dep . dep . dep()保存当前目标
价格集=调用价格上的dep.notify()来重新运行所有目标
让我们把这两个想法结合起来,完成我们的最终代码。
现在让我们看看会发生什么。
正是我们想要的!价格和数量真的是实时响应!只要价格或数量值更新,我们的总代码就会再次运行。
Vue文档中的这个插图现在应该开始有意义了。
你看到那个漂亮的紫色数据圈了吗?应该很眼熟吧!每个组件实例都有一个从getter收集依赖关系的服务观察器实例(蓝色)(红线)。稍后调用安装程序时,它会通知监视器它将导致组件再次呈现。这里有一些我自己注释的图片。
是的,现在更有意义了。
显然,Vue所做的事情可能更复杂、更令人惊讶,但现在你知道了基础。
总结:那么我们学到了什么?如何创建Dep类来收集依赖项并重新运行所有依赖项(通知)。如何创建一个观察器来管理我们正在运行的代码,它可能需要作为依赖项被定位。如何使用Object.defineProperty()创建getter和setter?
摘要
以上就是边肖介绍的Vue.js实现数据响应的方法。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!
版权声明:Vue.js实现数据响应的方法是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。