问题
我试图解决一个 VueJs 挑战。这个挑战有一组单元测试来验证我的代码的正确性。其中一些测试围绕输入文本字段进行。我按照通常的方式使用创建自定义输入组件,v-model但检查输入验证逻辑的测试失败。
安装组件时,v-model初始值为""(空字符串)。然后测试使用设置一个值setValue,然后使用检查输入是否具有正确的值customInput.element.value
const app = mount(App);
const customInput = app.find(".custom-input-field-a");
customInput.setValue("invalid input");
expect(customInput.element.value).toEqual("");
在setValue语句之后,输入元素触发一个input事件,由自定义组件处理。这个处理程序验证输入文本,然后发出一个input事件来更新 v-model。
发生这种情况时,不会更新任何内容,因为前一个值和下一个值等于""(此处没有“反应性”),因此语句customInput.element.value返回"invalid input"
代码
这是自定义组件:
<template>
<div class="custom-input">
<label :class="labelClasses" :for="name">{{ label }}</label>
<input
:class="`custom-input-${name}`"
:name="name"
:maxlength="3"
type="text"
:value="value"
@input="onInput"
@keypress="onlyLettersFilter"
/>
</div>
</template>
<script>
export default {
props: {
name: { type: String, required: true },
placeholder: { type: String, default: "some placeholder" },
label: String,
value: String,
},
computed: {
hasValue() {
return this.value?.length > 0;
},
labelClasses() {
return "custom-input--label " + (this.hasValue ? "active" : "");
},
},
methods: {
filterValue(input) {
let value = input.slice(0, 3);
value = value.toUpperCase().replace(/([^A-Z])+/g, "");
return value;
},
onInput(event) {
this.$emit("input", this.filterValue(event.target.value));
},
onlyLettersFilter(event) {
if (event.keyCode === 13) return true;
var key = String.fromCharCode(
!event.charCode ? event.which : event.charCode
);
// Accept only letters
var regex = new RegExp(/[a-zA-Z]+/);
if (regex.test(key)) {
return true;
}
event.preventDefault();
return false;
},
},
};
</script>
<style>
</style>
在这里您可以看到,在任何输入更改中,文本都会被过滤,删除不需要的字符。如果所有字符都无效,则结果为空字符串。
解决方法
作为一种解决方法,我设置了对输入元素的引用并直接更新了内容,而不使用 VueJs 功能。所有测试都通过了。
<template>
...
<input
...
ref="inputRef"
...
/>
...
</template>
<script>
export default {
...
methods: {
...
onInput(event) {
const value = this.filterValue(event.target.value);
// this prevents any invalid character in the input element when the model value doesn't change, when seting the value in unit tests
this.$refs.inputRef.value = value;
if (value === this.value) event.preventDefault();
else {
this.$emit("input", value);
}
},
}
...
}
</script>
我知道这是一个糟糕的解决方案,但我不知道更好。
在不使用 ref 和直接修改 HTML 组件的情况下,是否有更好、更简洁的方法来做到这一点?