Vue 下 input 输入拦截研究

前几天看面试题,其中提到 React 的 setState 何时为同步何时为异步。那篇文章提到要根据 isBatchingUpdate 来判断。当时我就信以为真了。

过了几天有时间就去看了下 React 源码,根本没有 isBatchingUpdate!之后依次翻阅历史版本,从 v18 一直到 v15.6,果真看到了。没想到这应该是 2018 的面试题吧。

正好突然想起了 React 对输入框的单向绑定,想看看具体实现。结果发现没有啥特殊逻辑。又想到公司的项目输入框,错误数据总是先显示出来,瞬间又被删除,体验不好。就想着封装一个 Vue 组件试试。

其实 2019 年我就写过方案了,只不过当时没有封装而已。现在来看,原理是正确的。

Input.vue 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<input ref="input" />
</template>

<script>
export default {
props: {
// 传入最新的值
value: { type: String, default: "" },
},
data() {
return {
// 本地缓存上一次老值
oldVal: "",
};
},
computed: {
// 输入框元素
input() {
return this.$refs.input;
},
},
watch: {
// 处理每次外层改变新值时候,要修正老值和输入框显示值
value(newVal, oldVal) {
this.oldVal = newVal;
this.input.value = newVal;
},
},
methods: {
listener(e) {
const target = e.target;
// 要想实现输入内容防抖,这里必须写成老值
// 后续等待外层改变新值时候,触发 watch->value 方法
target.value = this.oldVal;
this.$emit("input", e);
},
},
mounted() {
this.oldVal = this.value;
this.input.value = this.value;
this.input.addEventListener("input", this.listener);
},
beforeUnmount() {
this.input.removeEventListener("input", this.listener);
},
};
</script>

App.vue 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<Input :value="val" @input="onInput" />
</template>

<script>
import Input from "./components/Input";
export default {
components: { Input },
data() {
return {
val: "123",
};
},
methods: {
onInput(e) {
const val = e.target.value;
this.val = val.replace(/\D+/g, "");
},
},
};
</script>

在线看效果:https://codesandbox.io/s/vue-input-component-f412y

–END–