VueJS 观察属性和更改数据 [英] VueJS watching properties and changing data

查看:31
本文介绍了VueJS 观察属性和更改数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有三个字段:

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

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

观看:{p: 函数(nv,ov){this.v = this.t * nv/100;},t: 函数(nv,ov){this.v = nv * this.p/100;},v:函数(nv,ov){this.t = nv * this.p;}}

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

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

解决方案

你的价值观不收敛,因为你有一个不正确的功能.

如果total=100perc=11,则val=11:这是total * perc/100,好的.

如果total=100val=11,则perc=11:也就是total * val/100,可以.

如果 perc=11, val=11,则 total=100:这是val/perc * 100不是您使用的val * perc.

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

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

参见下面的演示,我修复了 v 观察器功能.(请注意,我必须使用一些 Math.round() 以便它们收敛而不改变输入数字 - 删除它们以了解我的意思.显然,这样做的缺点是数字被四舍五入.)

new Vue({el: "#app",数据: {吨:100,p: 10,五:10},手表: {p:函数(NV,OV){this.v = this.t * nv/100;},t:函数(NV,OV){this.v = Math.round(nv * this.p/100);},v:函数(nv,ov){this.t = Math.round(nv/this.p * 100);}}})

<script src="https://unpkg.com/vue"></script><div id="应用程序">总计:<br/><input type="number" v-model="t"/><小时/>百分比:<br/><input type="number" v-model="p"/><小时/>价值:<br/><input type="number" v-model="v"/>

修复该功能后,如果您不想要整数,请选择

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

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

new Vue({el: "#app",数据: {吨:100,p: 10,五:10},手表: {p:函数(NV,OV){this.v = this.t * nv/100;},t:函数(NV,OV){this.v = nv * this.p/100;},v:函数(nv,ov){this.t = nv/this.p * 100;}}})

<script src="https://unpkg.com/vue"></script><div id="应用程序">总计:<br/><input type="number" v-model="t"/><小时/>百分比:<br/><input type="number" v-model="p"/><小时/>价值:<br/><input type="number" v-model="v"/>

如果您不想要上述内容,您将必须处理变量之间的循环依赖.

解决循环依赖问题.

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

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

new Vue({el: "#app",数据: {吨:100,p: 10,五:10},方法: {更新P:功能(新P){this.p = newP;this.v = this.t * newP/100;},更新T:功能(新T){this.t = newT;this.v = newT * this.p/100;},更新V:功能(新V){this.v = newV;this.t = newV/this.p * 100;}}})

<script src="https://unpkg.com/vue"></script><div id="应用程序">总计:<br/><input type="number" :value="t" @input="updateT($event.target.value)"/><小时/>百分比:<br/><input type="number" :value="p" @input="updateP($event.target.value)"/><小时/>价值:<br/><input type="number" :value="v" @input="updateV($event.target.value)"/>

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

new Vue({el: "#app",数据: {tVal: 100,pVal: 10,值:10},计算:{p:{get() { 返回 this.pVal;},set(newP) { this.pVal = newP;this.vVal = this.tVal * newP/100;}},t:{get() { 返回 this.tVal;},set(newT) { this.tVal = newT;this.vVal = newT * this.pVal/100;}},v:{get() { 返回 this.vVal;},set(newV) { this.vVal = newV;this.tVal = newV/this.pVal * 100;}}},})

<script src="https://unpkg.com/vue"></script><div id="应用程序">总计:<br/><input type="number" v-model="t"/><小时/>百分比:<br/><input type="number" v-model="p"/><小时/>价值:<br/><input type="number" v-model="v"/>

Suppose I have three fields:

Value should change when either percent or total has changed. Total should change when value is changed.

Thus i created some watchers for those properties:

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;
  }
  }

Currently the watchers trigger each other and that is probably why it is not working correctly.

Check the fiddle: https://jsfiddle.net/jj65t449/

解决方案

Your values don't converge, because you have an incorrect function.

If total=100, perc=11, then val=11: which is total * perc/100, ok.

If total=100, val=11, then perc=11: which is total * val/100, ok.

If perc=11, val=11, then total=100: which is val / perc * 100, not val * perc as you are using.

Since you are using an invalid function, the total will be set to a crazy value, that will trigger a val update, that will trigger a total update again, snowballing them into infinite numbers (which is when the calculation stops, because they converged, as infinity=infinity).

So, if you correct your function, the infinite calculation will halt. Not because there is no cyclic dependency between those vars (there still is!), but because they will stop recalculating because the values will stop changing (they will converge).

See demo below, where I fixed the v watcher function. (Note that I had to use some Math.round() so they converge without changing the input numbers - remove them to see what I mean. The downside of this is, obviously, the numbers are rounded.)

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>

After fixing the function, options if you don't want round numbers

First fix the function. Now, some options.

You can just remove the Math.round(). The downside is that sometimes when you modify the v, the cycle will end up modifying v back, by 0.0000001. See demo below.

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>

If you don't want the above, you will have to handle the cyclic dependency between vars.

Working around the cyclic dependencies.

This is a common problem with Vue. There are some options, but they don't look pretty. Pick what suits you the best.

Changing the watchers into methods and removing 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>

Using internal variables to hold the values and use "settable" computed instead of watchers:

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>

这篇关于VueJS 观察属性和更改数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆