vue.js - 如何在 VueJS 中自己实现 v-model.number?
问题描述
我有一个用于数字输入的文本字段组件。基本上我只是包装 v-text-field 但准备自己实现它。它看起来像这样。
<template>
<v-text-field v-model.number = "content" />
</template>
<script>
export default {
name: 'NumericTextField',
props: [ 'value' ],
computed: {
content: {
get () { return this.value },
set (v) { this.$emit('input', f) },
},
}
}
</script>
这产生了用户反馈,当文本字段中包含字符串“10.2”,然后在“2”上退格,然后小数位被自动删除时,这很烦人。我想将这种行为更改为“10”。保留在文本字段中。我也想从第一原则来理解这一点,因为我对 Vue 比较陌生。
所以我尝试了这个作为第一次过去,这是我尝试过的最有启发性的事情。
<template>
<v-text-field v-model="content" />
</template>
<script>
export default {
name: 'NumericTextField',
props: [ 'value' ],
computed: {
content: {
get () { return this.value },
set (v) {
console.log(v)
try {
const f = parseFloat(v)
console.log(f)
this.$emit('input', f)
} catch (err) {
console.log(err)
}
},
},
}
}
</script>
我读到 v-model.number 是基于 parseFloat 的,所以我认为这样的事情一定会发生。所以它确实解决了小数位被自动删除的问题。但是......它甚至不会自动删除多余的字母。因此,如果我输入“10.2A”,即使我看到打印出“10.2”的控制台日志,“A”仍然存在。此外,还有一个更糟糕的错误特征。当我移动到字符串的开头并将其更改为“B10.2”时,它会立即替换为“NaN”。
所以我很想知道很多事情。为什么当我更改为 NaN 时文本正文的正文立即反应,但当我键入“10.2A”时没有立即反应?相关地,我是如何无意中摆脱自动删除小数位的?我什至还没有到达那部分。所以我误解了Vue中的数据流。
最后,我怎样才能最简单地提供一个文本框,该文本框将评估为放入我的数据模型中的数字,但又没有烦人的小数位自动删除?现有功能不会自动删除尾随字母,所以我猜小数位的自动删除是我的用户不喜欢的故意功能。
解决方案
我不是 100% 确定这一点,但请考虑如何v-model
在 components 上工作。它基本上是这样做的:
<v-text-field
v-bind:value="content"
v-on:input="content = $event.target.value"
/>
并考虑.number
修饰符是如何工作的。它通过 运行输入parseFloat
,但如果parseFloat
不起作用,它将保持原样。
因此,有了这种理解,我会期待以下内容:
当您输入“10.2”然后按退格键时,
"10."
将通过input
事件发出,parseFloat("10.")
将其转换为10
,v-on:input="content = $event.target.value"
将其分配给content
,并v-bind:value="content"
导致输入显示“10”。那么,这是预期的行为。当您输入“10.2”然后点击“A”时,
"10.2A"
将通过input
事件发出,parseFloat("10.2A")
将其转换为10.2
,v-on:input="content = $event.target.value"
将其分配给content
,并v-bind:value="content"
导致输入显示“10.2”。看起来它在导致输入显示“10.2”的最后一步失败了,因为状态content
被正确设置为10.2
. 如果您使用<input type="text" v-model.number="content" />
而不是<v-text-field v-model.number="content" />
,一旦您blur,文本字段将成功更新为“10.2”。所以看起来为什么<v-text-field>
不这样做的原因是由于 Vuetify 是如何处理这v-bind:value="content"
部分的。当您输入“10.2”然后输入“B”时,一开始
"B10.2"
将通过input
事件发出,parseFloat("B10.2")
将返回NaN
,因此.number
修饰符将保持原样,v-on:input="content = $event.target.value"
分配"B10.2"
给content
,并v-bind:value="content"
导致输入显示“ B10.2"。parseFloat("10.2A")
我同意返回10.2
但parseFloat("B10.2")
返回似乎不合适"B10.2"
。
最后,我怎样才能最简单地提供一个文本框,该文本框将评估为放入我的数据模型中的数字,但又没有烦人的小数位自动删除?
鉴于默认行为很奇怪,我认为您将不得不编写自己的自定义逻辑来转换用户的输入。例如。这样“10.2A”和“B10.2”都被转换为10.2
(或保持原样),因此小数点按您的意愿处理。像这样的东西(CodePen):
<template>
<div id="app">
<input
v-bind:value="content"
v-on:input="handleInputEvent($event)"
/>
<p>{{ content }}</p>
</div>
</template>
<script>
export default {
data() {
return {
content: 0,
};
},
methods: {
handleInputEvent(e) {
this.content = this.transform(e.target.value);
setTimeout(() => this.$forceUpdate(), 500);
},
transform(val) {
val = this.trimLeadingChars(val);
val = this.trimTrailingChars(val);
// continue your custom logic here
return val;
},
trimLeadingChars(val) {
if (!val) {
return "";
}
for (let i = 0; i < val.length; i++) {
if (!isNaN(val[i])) {
return val.slice(i);
}
}
return val;
},
trimTrailingChars(val) {
if (!val) {
return "";
}
for (let i = val.length - 1; i >= 0; i--) {
if (!isNaN(Number(val[i]))) {
return val.slice(0,i+1);
}
}
return val;
},
},
};
</script>
如果您希望输入字段实际更改,这$forceUpdate
似乎是必要的。但是,它似乎只适用于<input>
,而不适用于<v-text-field>
。这与我们在第二个要点中看到的一致。你可以自定义你的<input>
,让它看起来和表现得像<v-text-field>
。
我把它放在 a 里面,setTimeout
所以用户会看到“我试图输入这个,但它被删除了”而不是“我正在输入字符但它们没有出现”,因为前者在指示“你试图做什么”方面做得更好类型无效”。
或者,您可能希望对模糊事件进行转换,而不是在他们键入时进行转换。
推荐阅读
- java - 重新打开android应用程序时SQLlite表为空
- r - 如何根据字符串绑定列
- javascript - 在 React 中渲染选择
- python - 按年份和 total_vehicles 熊猫数据框求和
- netbeans-8 - 我想在我的代码中添加 GPA 但不幸的是没有工作
- javascript - 使用 URL 参数强制语言切换
- android - Android - 如何将文本视图附加到另一个文本视图的末尾?
- vim - 如何在 vim 中更改特定的“主题”颜色
- python - python scrapy从多个解析函数构建相同的项目:在循环中调用第二个解析函数
- javascript - 如何在 Vue.js 中创建/加载的组件/页面上显示模式