【问题标题】:Vue.js: error setting a computed propertyVue.js:设置计算属性时出错
【发布时间】:2016-10-26 14:04:15
【问题描述】:

在以下代码 (jsbin available here) 中,我有两个输入元素,一个范围和一个文本,通过计算属性绑定在一起。

var vm = new Vue({
  el: '#main-container',
  data: {
    sliderValue: 100,
  },
  computed: {
    actualValue: {
      get: function() {
        if (this.sliderValue <= 100) {
          return this.sliderValue;
        } else {
          return Math.round(this.sliderValue * 12.5 - 1150);
        }
      },
      /* set won't work for val > 100*/
      set: function(val) {
        if (val <= 100) {
          this.sliderValue = val;
        } else {
          this.sliderValue = Math.round((val + 1150)/12.5);
        }
      }
    }
  },
  methods: {
    
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
    <div id="main-container">
      <input type="range" v-model="sliderValue" min=1 max=132>
      <input type="text" v-model="actualValue">
      <p>Slider: {{sliderValue}}</p>
      <p>Actual: {{actualValue}}</p>
    </div>

范围从 1 到 132,它的 范围 在文本输入中映射为 [1..500],通过简单的转换(基本上它是一个线性映射,具有两个不同的斜率 [ 1..100] 和 [101..132]) 使用 actualValue 计算属性。

获取实际值按预期工作:拖动滑块正确地使用范围 [1..500] 内的适当值更新输入文本。

不过,我无法找到设置实际值的方法。我希望能够在文本输入中键入一个值,并使滑块的拇指根据逆变换 (val + 1150)/12.5 进行相应更新。

只要输入的数字在 [1..100] 范围内,它就可以工作,但对于 >100 的数字,它会“爆炸”,例如101 使sliderValue 跳到80892,然后actualValue 重新计算为1010000。据我了解,这是一个循环反馈场景。

我也尝试了其他方法(观看;v-on:更改文本输入;使用第三个变量)无济于事。

提前感谢您的任何建议!

【问题讨论】:

    标签: vue.js


    【解决方案1】:

    这是一个神奇的谜题,挑战了我很长时间!

    请看下面的截图。您的 sliderValue 和 actualValue 是字符串,而不是整数。当您将actualValue 设置为101 时,实际上是将其设置为"101" 的字符串值

    现在,你的sliderValue = ((actualValue + 1150)/12.5)

    "101" + 1150 = "1011150"(另一个字符串!,在开发者控制台中试试)

    这会打乱您的整个计算。现在你知道如何解决它了:-)

    你需要从这里获取 Vue 开发工具:https://github.com/vuejs/vue-devtools

    编辑:对评论 #3 的回应

    这里是修改后的jsBin:http://jsbin.com/mahejozeye/1/edit?html,js,output

    唯一的区别是在map2 函数中引入了两个console.log 语句。这可以帮助您确定您的非线性映射函数是否正常工作。如果你保持你的开发者控制台打开,你会看到这个函数发生了什么。

    • 案例 1:当您使用文本框设置值 radius = 25 时,您的 sliderRadius 被设置为 111.55518394648828,并且您的 radius 再次被重新计算为 25。所以它绕了一圈,这里一切都稳定了。

    • 案例 2:当您设置值 radius = 55 时,您的 sliderRadius 通过您的非线性 ma​​p2() 函数设置为 173.03607214428857,该函数将半径重置为 @ 987654342@

    显然存在循环依赖问题。您的sliderRadiusradius 非常依赖彼此,因此radius 无法取51 到58 之间的值。

    您需要评估它发生的原因,因为它与您定义的非线性映射函数有很大关系。当radius 可以取55 的稳定值时(通过map2 函数),那么您当前的问题将得到解决。

    【讨论】:

    • 好收获!事实上,我在 Photoshop HTML 面板(Chromium 嵌入式框架)的上下文中工作,在原型设计/测试交互时,我在 jsbin 中重建了一个更简单的场景版本:我的错误,我输入了类型编号 I曾经在CEF中,变成了type text。尽管如此,我在 Matt Kelliher 的回答中也遇到了同样的问题——我最终用更小的范围的步长解决了,并且在 setter 中没有 Math.round。谢谢!
    • 是的,Math.round() 是您原始公式中的一个错误。如果将actualValue 设置为101,sliderValue 将变为100.08 并立即四舍五入为100。这将actualValue 拉回100。但真正的问题是整数和字符串加法。 Javascript 或任何编程语言首先不应该允许这样的事情。不过,就目前而言,您可以获得 Vue 开发工具,它帮助我发现了错误。
    • @DavideBarranca 我已经修改了上面的答案,因为还有更多信息,我无法将其放入评论中。我已经克隆了你的 jsBin,这样我就可以在 map2 函数中包含两个 console.log 语句,看看那里发生了什么。显然radiussliderRadius 之间存在循环依赖问题(通过非线性映射函数 - map2),因此它无法获取某些值。此 map2 函数需要进行修改,使其在 51 到 58 之间的值保持稳定。
    • 谢谢你,Mani,我周末可以看看,然后在这里报告
    【解决方案2】:

    最简单的解决方法是将输入类型设置为number

    <input type="number" v-model="actualValue">
    

    或者您可以将值转换为整数,例如:

      set: function(val) {
        var intVal = parseInt(val, 10);
    
        if (!isNaN(intVal)) {
          if (intVal <= 100) {
            this.sliderValue = Math.max(1, intVal);
          } else {
            this.sliderValue = Math.min(132, Math.round((intVal + 1150) / 12.5));
          }
        }
      }
    

    【讨论】:

    • 效果很好,请在此处查看jsbin。我唯一担心的是,虽然数字输入实际上可以显示所有 500 个值,但实际值跳跃(500、488、472)基本上是因为滑块只有 32 个插槽来覆盖 400 个值。我已经更改了代码,看到一个新的jsbin,因此范围的步长为 0.1,并且我已经从 set 函数中删除了 Math.round
    猜你喜欢
    • 2016-08-09
    • 2017-08-26
    • 1970-01-01
    • 2017-09-16
    • 2019-08-08
    • 2017-10-06
    • 2017-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多