一直在用 react,对于控制 input 输入框内容处理起来非常方便。可是在 vue 项目中,这个处理就略显麻烦。查阅网上资源,大部分都是给出控制 keyup
keydown
等,输入时候进行 replace
操作,我认为是有问题的。
比如有一个需求,要求支持输入 16 进制颜色值,并且为大写显示。
react 实现
用 react 来实现,不论是传统 class
类写法,还是新的 useHooks
写法都是很容易的。
主要是因为只需要监听输入内容,如果符合要求直接写入 state
就可以了,而 input 输入框的值绝对和 state
一致。
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
| 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)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| .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
状态。
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
| <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> </style>
|
vue 组件封装方案
为了省事,可以把 input 进行封装成组件。
下面例子中,仅仅封装了 input
value
功能。
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
| <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 思路基本一致:
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
| <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> </style>
|
–END–