VueJS 观察属性和改变数据

Posted

技术标签:

【中文标题】VueJS 观察属性和改变数据【英文标题】:VueJS watching properties and changing data 【发布时间】:2018-08-13 17:25:51 【问题描述】:

假设我有三个字段:

当百分比或总数发生变化时,值应该会发生变化。 当值改变时,总计应该改变。

因此我为这些属性创建了一些观察者:

watch:
  p: function(nv,ov)
    this.v = this.t * nv / 100;
  ,
  t: function(nv,ov)
     this.v = nv * this.p / 100;
  ,
  v: function(nv,ov)
    this.t = nv * this.p;
  
  

目前观察者相互触发,这可能是它无法正常工作的原因。

检查小提琴:https://jsfiddle.net/jj65t449/

【问题讨论】:

绕过无限更新的一种方法是使用带有支持私有数据值的计算值。 jsfiddle.net/jwgcptLh/6 【参考方案1】:

你的值不收敛,因为你有一个不正确的函数

如果total=100perc=11,那么val=11:就是total * perc/100,ok。

如果total=100val=11,那么perc=11:就是total * val/100,好吧。

如果perc=11val=11,那么total=100:这是val / perc * 100不是你使用的val * perc .

由于您使用了无效函数,总数将被设置为一个疯狂的值,这将触发 val 更新,这将再次触发 total 更新,将它们滚雪球成无限数(这是当计算停止,因为它们收敛,如infinity=infinity)。

因此,如果您更正函数,无限计算将停止。不是因为这些变量之间没有循环依赖(仍然存在!),而是因为它们将停止重新计算,因为值将停止变化(它们将收敛)。

请参阅下面的演示,我在其中修复了 v 观察程序功能。 (请注意,我必须使用一些 Math.round() 以便它们在不更改输入数字的情况下收敛 - 删除它们以了解我的意思。显然,这样做的缺点是数字是四舍五入的。)

new Vue(
  el: "#app",
  data: 
    t: 100,
    p: 10,
    v: 10
  ,
  watch: 
    p: function(nv, ov) 
      this.v = this.t * nv / 100;
    ,
    t: function(nv, ov) 
      this.v = Math.round(nv * this.p / 100);
    ,
    v: function(nv, ov) 
      this.t = Math.round(nv / this.p * 100);
    
  
)
<script src="https://unpkg.com/vue"></script>
<div id="app">
  Total:<br/>
  <input type="number" v-model="t" />
  <hr/> Percent: <br/>
  <input type="number" v-model="p" />
  <hr/> Value:
  <br/>
  <input type="number" v-model="v" />
</div>

修复函数后,如果不想要整数的选项

首先修复函数。现在,一些选项。

您可以删除Math.round()。不利的一面是,有时当您修改v 时,循环将最终将v 修改回0.0000001。请参阅下面的演示。

new Vue(
  el: "#app",
  data: 
    t: 100,
    p: 10,
    v: 10
  ,
  watch: 
    p: function(nv, ov) 
      this.v = this.t * nv / 100;
    ,
    t: function(nv, ov) 
      this.v = nv * this.p / 100;
    ,
    v: function(nv, ov) 
      this.t = nv / this.p * 100;
    
  
)
<script src="https://unpkg.com/vue"></script>
<div id="app">
  Total:<br/>
  <input type="number" v-model="t" />
  <hr/> Percent: <br/>
  <input type="number" v-model="p" />
  <hr/> Value:
  <br/>
  <input type="number" v-model="v" />
</div>

如果你不想要上面的,你将来处理变量之间的循环依赖。

解决循环依赖问题。

这是 Vue 的常见问题。有一些选择,但它们看起来并不漂亮。选择最适合您的。

观察者改为方法并删除v-model

new Vue(
  el: "#app",
  data: 
    t: 100,
    p: 10,
    v: 10
  ,
  methods: 
    updateP: function(newP) 
      this.p = newP;
      this.v = this.t * newP / 100;
    ,
    updateT: function(newT) 
      this.t = newT;
      this.v = newT * this.p / 100;
    ,
    updateV: function(newV) 
      this.v = newV;
      this.t = newV / this.p * 100;
    
  
)
<script src="https://unpkg.com/vue"></script>

<div id="app">
  Total:<br/>
  <input type="number" :value="t" @input="updateT($event.target.value)" />
  <hr/> Percent: <br/>
  <input type="number" :value="p" @input="updateP($event.target.value)" />
  <hr/> Value:
  <br/>
  <input type="number" :value="v" @input="updateV($event.target.value)" />
</div>

使用内部变量保存值并使用“settable”计算代替观察者:

new Vue(
  el: "#app",
  data: 
    tVal: 100,
    pVal: 10,
    vVal: 10
  ,
  computed: 
    p: 
      get()  return this.pVal; ,
      set(newP)  this.pVal = newP; this.vVal = this.tVal * newP / 100; 
    ,
    t: 
      get()  return this.tVal; ,
      set(newT)  this.tVal = newT; this.vVal = newT * this.pVal / 100; 
    ,
    v: 
      get()  return this.vVal; ,
      set(newV)  this.vVal = newV; this.tVal = newV / this.pVal * 100; 
    
  ,
)
<script src="https://unpkg.com/vue"></script>
<div id="app">
  Total:<br/>
  <input type="number" v-model="t" />
  <hr/> Percent: <br/>
  <input type="number" v-model="p" />
  <hr/> Value:
  <br/>
  <input type="number" v-model="v" />
</div>

【讨论】:

感谢@acdcjunior 的详细回答。事实上,我主要对如何处理循环依赖感兴趣。不正确的功能只是将小提琴放在一起时的副作用。我转向了具有可设置计算属性的解决方案(Bert 已经建议),因为将观察者与 Math.round 结合使用会导致一些可用性问题,您可以在此处看到 jsfiddle.net/rmzabmv3 。如果您减少总数,例如使用数字向下箭头所有小于 5 的数字都四舍五入为 0。 是的。完全有道理。很好的解决方案。

以上是关于VueJS 观察属性和改变数据的主要内容,如果未能解决你的问题,请参考以下文章

vuejs 计算属性 - 何时触发更新?

TypeScript VueJS:使用具有计算属性的观察器

vuejs2:我怎样才能摧毁一个观察者?

swift学习第十四天:属性监听器

VueJS 观察插入的参数

对挂载中的属性的更改未触发在 VueJS 中计算