手机版

Vue数据双向绑定的深入探索

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

前言

所有用过vue的朋友都会觉得,哇,这个框架对开发者太友好了,差点笑出来。

确实,使用过vue框架进行开发的人,会觉得不需要写很多东西来操作dom和bom,让开发者更容易关注操作逻辑的思考和实现,省了很多事!

我直接从开发本地js和jq到使用vue。我也很喜欢这个框架,没事做。我去看了它的一些实现原则。

Vue是一个mvvm框架,也就是数据的双向绑定,即当数据改变时,视图改变,当视图改变时,数据同步改变。这就是vue的精髓。值得注意的是,我们所说的数据双向绑定一定是针对UI控件的,非UI控件不会涉及数据双向绑定。单向数据绑定是使用redux等状态管理工具的先决条件。

我们来介绍一下vue一个非常强大的功能,那就是双向数据绑定,也就是我们在项目中使用的v-model指令。

在官方文件vue '表格输入绑定'一节中介绍了v型模型。

对于表单,每个人都必须非常熟练,对于项目中输入、文本区域和选择标签的使用没有什么好说的

官方的v型是语法糖。为什么这么说?这里有一个例子:

div id=' test 1 ' input v-model=' input ' spannput : { { input } }/span/div如上所述,它是一个使用v-model的简单双向绑定。当我们改变输入变量的值时,也就是我们在输入框中写入内容时,span标签中的插值会同步更新我们刚刚输入的值。

其实,上面也可以这样写:

Div id=' test1 '输入on:输入=' input=$ event。目标。value ' v-bind : value=' input ' spannput 3360 { { input } }/span/div好了,好久不见了,现在我们言归正传

我想比较一下react和angular的双向绑定实现,不知道,哈哈哈,就说vue,别扯了

反应性响应系统

以尤雨溪的老大哥做vue测试为例(购物车示例)

div id=' app ' div span price:/span put v-model . number=' price '/div span quantity:/span put v-model . number=' quantity '/div p price:{ { price } }/ppquantity:{ { quantity } }/Total PP:{ { Total } }/p/div data(){ return { price : 5,quantity : 3 } },computed 3: { Total(){ return this。价格*这个。数量;}}当我们使用输入框的值时,下面的总数将被更新,与输入值相对应的变量也将被更新

哇,太神奇了。为什么呢?这不是正常的JavaScript编程方式!

因为当我们用原生js编写时,它是这样的:

让价格=5;让数量=3;让总数=价格*数量;//等于15。价格=10;//更改价格;console.log(总计);//答对了,打印还是15。我们需要找到一种方法,将总数放在另一个时间运行计算,并在我们的价格和数量发生变化时执行

让价格=5;让数量=3;让total=0;let storage=[];//存储要计算的操作,变量变化时执行let target=()={ total=price * quantity;}函数record(){ storage . push(target);}函数replay(){ storage . foreach(run=run());}记录();target();价格=10;console.log(总计);//仍然是15 replay();console.log(总计);//执行的结果是30个目标,但这绝对不是vue用来扩展用法的方式。我们使用ES6类作为可维护的扩展来实现一个标准的观察者模式依赖类

class Depend { constructor(){ this . subscribers=[];} depend() { if(target this,this . subscribers . includes(target)){ this . subscribers . push(target);} } notify(){ this . subscribers . foreach(sub=sub());} }//来执行上面写的class const dep=new Depend();让价格=5;让数量=3;让total=0;let target=()={ total=price * quantity };dep . depend();target();console.log(总计);//total为15price=10console.log(总计);//因为没有执行目标,所以还是15dep . notify();console.log(总计);//执行存储的目标,总数为30。以便为每个变量设置一个依赖类。为了很好地控制监控更新的匿名函数的行为,我们对上面的代码进行了一些调整:

let target=()={ total=price * quantity };dep . depend();target();修改为:

观察者(()={ total=price * quantity });然后我们在观察器函数中设置并执行上面的结果

函数观察器(fn){ target=fn;dep . depend();target();target=null//Reset,下次等待存储执行}这是官方文档中提到的订阅者模式:每次执行watcher函数时,将参数fn设置为我们的全局目标属性,调用dep.depend()将目标添加为订阅者,调用并重置。

然后继续

我们的目标是为每个变量设置一个Depend类,但是这里有一个问题:

先保存数据:

Letdata={价格: 5,数量: 3}假设我们的每个属性都有自己的内部Depend类

当我们运行代码时:

watcher(()={ total=data.price * data . quantity })已经访问了data . price值,并希望price属性的Depend类将我们的匿名函数(存储在目标中)推送到它的订阅者数组(通过调用dep.depend())。在访问了data.quantity之后,我还希望quantity属性的Depend类将这个匿名函数(存储在目标中)推送到它的订阅者数组中。

如果有另一个只访问data.price的匿名函数,希望只推送到price属性Depend类。

您想什么时候打电话给价格订阅者的dep.notify()。定价的时候想给他们打电话。为此,我们需要一些方法来挂钩数据属性(价格或数量),这样我们就可以在访问目标时将其保存到我们的订阅者数组中,并在更改时运行存储在我们的订阅者数组中的函数。我们走吧

对象。定义一个属性来解决这个问题

函数Object.defineProperty是一个简单的ES5 JavaScript。它允许我们为属性定义getter和setter函数。继续啃

让数据={ price: 5,quantity : 3 };让value=data . price object . definepreproperty(data,' price ',{getter () {console.log(`获取price : ${value} `)的值);返回值;},setter(newValue) {console.log(`更改价格的值' : $ { NewValue } `);value=newValue} })total=data . price * data . quantity;data.price=10//改变价格的价值。上面,获取和修改值的操作是通过defineProperty方法为价格设置的

如何将此defineProperty方法添加到所有数据对象中以设置值

你还记得Object.keys的方法吗?返回对象键数组,让我们修改上面的代码

让数据={ price: 5,quantity : 3 };Object.keys(数据)。forEach(key={ let value=data[key];Object.defineproperty (data,key,{getter () {console.log(`获取${key} : ${value} '的值');返回值;},setter(NewValue){ console . log(` change $ { key } value ' : $ { NewValue } `);value=newValue} })})total=data . price * data . quantity;data.price=10//改变价格的价值,然后是上面的事情。每次得到key的值后,我们希望key能记住这个匿名函数(target),这样当key的值发生变化时,就会触发这个函数重新计算。总体思路如下:

执行getter函数时,请记住这个匿名函数。当值改变时,再次运行它。执行setter函数时,运行保存的匿名函数并保存当前值。根据上面定义的依赖类:

Getter执行,调用dep.depend()保存当前的目标setter执行,调用key上的dep.notify()并重新运行所有目标,将上述内容组合在一起

让数据={ price: 5,quantity : 3 };让total=0;让target=nullclass Depend { constructor(){ this . subscribers=[];} depend(){ if(target this . subscribers . includes(target)){ this . subscribers . push(target);} } notify(){ this . subscribers . foreach(sub=sub());} } Object.keys(数据)。forEach(key={ let value=data[key];const dep=new Deon();object . definepreproperty(data,key,{ getter(){ dep . depend();返回值;},setter(new value){ value=new value;dep . notify();} })});函数观察器(fn){ target=fn;target();target=null} watcher(()={ total=data . price * data . quantity;});至此,vue的数据双向绑定已经实现。当我们改变价格和数量的值时,总量会实时变化

然后让我们看看vue文档中提到的这张插图:

你觉得这张图熟悉吗?与我们上面研究的过程相比,这个图中的数据和守望者非常清晰,大致思路是这样的。可能vue的内部实现和封装比我研究过程的内容要大得多,复杂得多,但是有了这样的过程思路,估计看vue的双向绑定源代码就能理解了。

听说vue3.0要用ES6提供的代理劫持这些数据,效率更高。我很期待!

参考学习原文(可能需要翻墙,毕竟是外站)

摘要

以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。有问题可以留言交流。谢谢你的支持。

版权声明:Vue数据双向绑定的深入探索是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。