Vue.js:设置计算 属性 时出错
Vue.js: error setting a computed property
在以下代码 (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 计算 属性.
获取 actualValue 按预期工作:拖动滑块正确地使用范围 [1..500] 中的适当值更新输入文本。
不过,我找不到设置 actualValue 的方法。我希望能够在文本输入中键入一个值,并使滑块的拇指相应地更新为逆变换 (val + 1150)/12.5.
只要输入的数字在 [1..100] 范围内,它就可以工作,但它 "explodes" 对于 >100 的数字,例如101 使 sliderValue 跳到 80892,然后 actualValue 被重新计算为 1010000。据我了解,这是一个循环反馈场景。
我也尝试过替代方法(观看;v-on:更改文本输入;使用第三个变量)无济于事。
提前感谢您的任何建议!
这是一个神奇的谜题,挑战了我很长时间!
请看下面的截图。您的 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
通过非线性 map2( ) 函数,它将半径重置为 51.29869180420927
显然存在循环依赖问题。您的 sliderRadius
和 radius
非常依赖彼此,因此 radius
无法取 51 和 58 之间的值。
你需要评估它为什么会发生,因为它与你定义的非线性映射函数有很大关系。一旦radius
可以稳定取值55(通过map2函数),那么你现在的问题就解决了。
最简单的解决方法是将输入类型设置为 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 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 计算 属性.
获取 actualValue 按预期工作:拖动滑块正确地使用范围 [1..500] 中的适当值更新输入文本。
不过,我找不到设置 actualValue 的方法。我希望能够在文本输入中键入一个值,并使滑块的拇指相应地更新为逆变换 (val + 1150)/12.5.
只要输入的数字在 [1..100] 范围内,它就可以工作,但它 "explodes" 对于 >100 的数字,例如101 使 sliderValue 跳到 80892,然后 actualValue 被重新计算为 1010000。据我了解,这是一个循环反馈场景。
我也尝试过替代方法(观看;v-on:更改文本输入;使用第三个变量)无济于事。
提前感谢您的任何建议!
这是一个神奇的谜题,挑战了我很长时间!
请看下面的截图。您的 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
通过非线性 map2( ) 函数,它将半径重置为51.29869180420927
显然存在循环依赖问题。您的 sliderRadius
和 radius
非常依赖彼此,因此 radius
无法取 51 和 58 之间的值。
你需要评估它为什么会发生,因为它与你定义的非线性映射函数有很大关系。一旦radius
可以稳定取值55(通过map2函数),那么你现在的问题就解决了。
最简单的解决方法是将输入类型设置为 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));
}
}
}