我正在开发一个v文本字段,当您按Enter或从文本字段模糊(失去焦点)时,将允许1 + 1之类的简单数学表达式生成2。到目前为止,这是我的代码。
<template>
<v-text-field
:rules="rules"
@blur="compute"
@keydown.enter="compute"
v-model="localValue"
validate-on-blur
/>
</template>
<script>
import { create, all } from 'mathjs'
const math = create(all)
export default {
name: "NumericTextField",
props: ["value"],
data () {
return {
localValue: this.value,
}
},
watch: {
value (v) {
this.localValue = v
},
},
methods: {
compute () {
try {
const result = math.evaluate(this.localValue)
this.$emit("input", result)
} catch (e) {
console.log("compute error", e)
}
},
},
computed: {
rules () {
return [v => /^([0-9]*[.])?[0-9]+$/.test(v) || "Must be numeric."]
},
},
}
</script>
有一个奇怪的行为,就是当我模糊文本字段时,通过跳到下一个文本字段,使validate-on-blur生效,@ blur也会计算结果。验证在这场比赛中获胜,但我仍然看到违规错误,但结果很快变为了应该有效的数字答案。具体来说,我输入1 + 1(由于其中有加号,因此不是数字)。当我按Tab键时,文本框将更改为2(非常好),并且还会出现一个验证错误,抱怨1 + 1不是数字。那是不希望的。如果结果是数字,我希望验证考虑到这一点。但是我不知道如何控制这种比赛状态。
我已经尝试过,并且成功锁定了页面的表单,并通过给我的表单ref并随后在末尾调用this。$ refs.myForm.validate()来显式重新验证字段上的所有表单。计算。但这使我的组件不是真正可重用的,因为它需要了解父窗体。此外,它正在重新评估所有基于模糊的表单验证,如果一页纸很多,我认为这会变得昂贵。
有没有办法控制比赛条件?还是可以解决?
答案 0 :(得分:1)
我认为没有任何方法可以阻止Vuetify的validate-on-blur
首先运行。因此,这是您可以在没有它的情况下进行偷偷摸摸的解决方法。您的模板如下所示:
<template>
<v-text-field
:rules="rules"
@blur="validate"
@keydown.enter="validate"
@focus="clearRules"
@input="clearRules"
v-model="localValue"
/>
</template>
由于您不会使用validate-on-blur
,因此需要手动编写rules
的设置和清除代码,否则它们将立即应用于输入。定义一个带有空数组的数据属性:
data() {
return {
rules: []
}
},
每次聚焦字段或发生输入时,rules
将被清除。现在所需要做的就是在每个blur
/ keydown
上运行一个validate方法,它将:1)设置规则,2)计算结果:
validate() {
this.setRules();
this.compute();
},
setRules() {
this.rules = [v => /^([0-9]*[.])?[0-9]+$/.test(v) || "Must be numeric."];
},
compute() {
try {
const result = math.evaluate(this.localValue)
this.$emit("input", result)
} catch(e) {
console.log("compute error", e)
}
},
这是工作示例(我使用eval
而不是您的mathjs
库):
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
// ...
rules: []
}
},
methods: {
validate() {
this.setRules();
this.compute();
},
setRules() {
this.rules = [v => /^([0-9]*[.])?[0-9]+$/.test(v) || "Must be numeric."];
},
compute() {
try {
this.localValue = eval(this.localValue);
} catch(e) {
// console.log("compute error", e)
}
},
clearRules() {
this.rules = [];
}
}
})
<div id="app">
<v-app>
<v-text-field
:rules="rules"
@blur="validate"
@keydown.enter="validate"
@focus="clearRules"
@input="clearRules"
v-model="localValue"
></v-text-field>
</v-app>
</div>
<!-- LIBRARIES -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
来自here的想法,适合与blur
一起使用。