Vue input 拦截控制输入内容
· 阅读需 4 分钟
一直在用 react,对于控制 input 输入框内容处理起来非常方便。可是在 vue 项目中,这个处理就略显麻烦。查阅网上资源,大部分都是给出控制 keyup
keydown
等,输入时候进行 replace
操作,我认为是有问题的。
比如有一个需求,要求支持输入 16 进制颜色值,并且为大写显示。
react 实现
用 react 来实现,不论是传统 class
类写法,还是新的 useHooks
写法都是很容易的。
主要是因为只需要监听输入内容,如果符合要求直接写入 state
就可以了,而 input 输入框的值绝对和 state
一致。
import React, {useState} from 'react'
import ReactDOM from 'react-dom'
import './styles.css'
function App() {
const [color, setColor] = useState('')
const handleInput = e => {
const val = e.target.value
if (/^[\dA-Fa-f]{0,6}$/g.test(val)) {
setColor(val.toUpperCase())
}
}
return (
<div>
<div className="input">
<p>#</p>
<input onInput={handleInput} value={color}/>
</div>
<p className="show">You input is: {color}</p>
</div>
)
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App/>, rootElement)
.input {
display: flex;
align-items: center;
padding-bottom: 1px;
width: 150px;
height: 30px;
border-bottom: 1px solid #aaa;
}
.input p {
margin-right: 4px;
height: 20px;
}
.input input {
width: 100%;
height: 100%;
border: 0;
outline: none;
}
.show {
margin-top: 50px;
}
vue 实现
由于 v-model
会自动绑定数据,导致没办法拦截输入,所以不能使用。而 keyup
keydown
经过测试,体验也非常不好,还不如 input
省心。
keydown
可以做到精准拦截,通过return false
让输入内容不能输入到 input 上,但该方法也导致无法直接获取用户输入的内容(只能获取键盘按键 key 值)。keyup
和input
实现方式应该一致,但我一开始实验时候没想到复写 value,导致体验不太好,具体细节原因忘记了。
实现控制输入的核心在于,先获取用户输入内容,如果合格则设置新值,不合格还要还原成旧值!这个过程存在新值和旧值的比对,所以要记录好旧值。
同时,需要改写 state
值以及 input 的 value
值,因为手动修改 input 值需要自己改变 state
状态。
<template>
<div>
<div class="input">
<p>#</p>
<input @input="onInput" :value="color">
</div>
<p class="show">You input is: {{color}}</p>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
color: ""
}
},
methods: {
onInput(e) {
const lastVal = this.color
const newVal = e.target.value
const valid = /^[\dA-Fa-f]{0,6}$/g.test(newVal)
e.target.value = valid ? newVal.toUpperCase() : lastVal
this.color = valid ? newVal.toUpperCase() : lastVal
}
}
}
</script>
<style>
<!--
样式参考 react 方案中 css 内容
-->
</style>
vue 组件封装方案
为了省事,可以把 input 进行封装成组件。
下面例子中,仅仅封装了 input
value
功能。
<template>
<input @input="onInput" :value="value">
</template>
<script>
export default {
props: ['value'],
data() {
return {
val: this.value
}
},
watch: {
value(newVal, oldVal) {
this.val = newVal
}
},
methods: {
onInput(e) {
const newVal = e.target.value
e.target.value = this.val
this.$emit('input', newVal)
}
}
}
</script>
调用上和 react 思路基本一致:
<template>
<div>
<div class="input">
<p>#</p>
<Input @input="onInput" :value="color"/>
</div>
<p class="show">You input is: {{color}}</p>
</div>
</template>
<script>
import Input from './Input'
export default {
name: 'App',
components: {Input},
data() {
return {
color: ''
}
},
methods: {
onInput(val) {
const upper = val.toUpperCase()
if (/^[\dA-F]{0,6}$/g.test(upper)) {
this.color = upper
}
}
}
};
</script>
<style>
<!--
样式参考 react 方案中 css 内容
-->
</style>