在 vue 中的项目,基于 VUX-UI 开发,一个常见的需求:
- 、金额输入框
- 、弹出数字键盘
- 、仅支持输入两位小数,限制最大11位数,不允许0开头
第一,首先想到额就是在 VUX-UI 中制定 type=number。-- 不可行
VUX 中的文档和代码说明,type=number 不支持 maxLength,会报错,而且没有正则替换的处理或者钩子函数,只有输入后提示校验信息。
第二,基于 VUX 中 XInput 封装,有如下问题
1)两层 v-model,正则替换的值不会触发 input 框渲染
解决:currentValue 赋值为 foramttedValue,放入 setTimeout(func ,0) 中,让 input 框先渲染为正则替换前的值,再渲染为替换后的值
- currentValue(val, oldVal) {
- // 调用filter过滤数据
- let formattedValue = this.filter(val);
- if (this.type === 'number') {
- formattedValue = this.typeNumberFilter(formattedValue, oldVal);
- }
- if (val !== formattedValue || val === '') {
- setTimeout(() => {
- this.currentValue = formattedValue;
- }, 0);
- }
- this.$emit('input', formattedValue);
- },
View Code
2)数字键盘 input type=number,会导致 maxlength 失效,无法限制长度
解决:用 slice(0, max) 处理
- if (formattedValue.length > this.max) {
- formattedValue = formattedValue.slice(0, this.max);
- }
View Code
3)数字键盘 input type=number ,连续输入小数点... 导致实际值和显示值不一致
解决:用原生的 inputElement.value = oldValue 处理
- const inputEle = this.$children[0].$refs.input;
- // TODO: 待大范围验证:处理连续输入..后,type=number的input框会把值修改为''的问题;fastclick导致type=number报错
- // 问题描述: 1.00. 不会触发值改变,1.00.不会触发值改变,1.00.【\d\.】都会把值修改为空字符串''。hack处理的条件说明如下:
- // 1、当校验后是空值,(因input=number,formattedValue为''表明 原始newVal也为'')
- // 2、输入框拿到的是空值(因input=number导致输入框立即被赋予空值。点击清除按钮时,这里input输入框还是上次的值)
- // 3、上次输入大于两位(避免最后一位无法删除的问题。最后一位删除时,oldVal.length === 1)
- if (formattedValue === '' && inputEle.value === '' && oldVal && oldVal.match(/^(\d)[\d.]+/)) {
- formattedValue = oldVal;
- }
- setTimeout(() = >{
- inputEle.value = formattedValue;
- },
- 0);
View Code
4)IOS 中数字键盘有 %$* 等特殊字符
解决:用原生的 inputElement.onkeydown 监听事件,非数字和退格和小数点直接 return 事件
- mounted() {
- if (this.type === 'number') {
- const inputEle = this.$refs.xinput.$refs.input;
- // eslint-disable-next-line
- inputEle.onkeydown = (e) = >{
- const keyCode = e.keyCode;
- if (!this.isBackspace(keyCode) && !this.isDot(keyCode) && !this.isNumber(keyCode)) {
- // 其他按键
- e.preventDefault();
- e.stopPropagation();
- return false;
- }
- };
- }
- }
View Code
第三,其他说明
为什么不用 type=tel?
type=tel 在 ios 中没有小数点
第四,全部代码
- <template>
- <XInput :title="title" :max="currentMax" :min="currentMin" :type="type"
- v-model="currentValue" @on-focus="onFoucus()" @on-blur="onBlur()" :show-clear="showClear"
- :placeholder="placeholder" ref="xinput">
- <template v-if="$slots.label" slot="label">
- <slot name="label">
- </slot>
- </template>
- <template v-if="$slots.right" slot="right">
- <slot name="right">
- </slot>
- </template>
- </XInput>
- </template>
- <script>
- export
- default {
- data() {
- return {
- currentValue:
- this.value,
- };
- },
- computed: {
- currentMax() {
- return (this.type === 'number') ? undefined: this.max;
- },
- currentMin() {
- return (this.type === 'number') ? undefined: this.min;
- }
- },
- props: {
- title: String,
- max: Number,
- min: Number,
- type: String,
- showClear: {
- type: Boolean,
- default:
- true,
- },
- placeholder: String,
- value: [String, Number],
- filter: {
- type: Function,
- default:
- (value) = >{
- let formattedValue = '';
- const match = value.match(/^([1-9]\d*(\.[\d]{0,2})?|0(\.[\d]{0,2})?)[\d.]*/);
- if (match) {
- formattedValue = match[1];
- }
- return formattedValue;
- },
- }
- },
- watch: {
- currentValue(val, oldVal) {
- // 调用filter过滤数据
- let formattedValue = this.filter(val);
- if (this.type === 'number') {
- formattedValue = this.typeNumberFilter(formattedValue, oldVal);
- }
- if (val !== formattedValue || val === '') {
- setTimeout(() = >{
- this.currentValue = formattedValue;
- },
- 0);
- }
- this.$emit('input', formattedValue);
- },
- value(value) {
- this.currentValue = value;
- },
- },
- methods: {
- onFoucus() {
- this.$emit('on - focus');
- },
- onBlur() {
- this.$emit('on - blur');
- },
- typeNumberFilter(val, oldVal) {
- const inputEle = this.$refs.xinput.$refs.input;
- let formattedValue = val;
- // 由于type=number不支持maxLength,用slice模拟
- if (formattedValue.length > this.max) {
- formattedValue = formattedValue.slice(0, this.max);
- }
- // TODO: 待大范围验证:处理连续输入..后,type=number的input框会把值修改为''的问题;fastclick导致type=number报错
- // 问题描述: 1.00. 不会触发值改变,1.00.不会触发值改变,1.00.【\d\.】都会把值修改为空字符串''。hack处理的条件说明如下:
- // 1、当校验后是空值,(因input=number,formattedValue为''表明 原始newVal也为'')
- // 2、输入框拿到的是空值(因input=number导致输入框立即被赋予空值。点击清除按钮时,这里input输入框还是上次的值)
- // 3、上次输入大于两位(避免最后一位无法删除的问题。最后一位删除时,oldVal.length === 1)
- if (formattedValue === '' && inputEle.value === '' && oldVal && oldVal.match(/^(\d)[\d.]+/)) {
- formattedValue = oldVal;
- }
- setTimeout(() = >{
- inputEle.value = formattedValue;
- },
- 0);
- return formattedValue;
- },
- isBackspace(keyCode) {
- return keyCode === 8;
- },
- isDot(keyCode) {
- return keyCode === 46 || keyCode === 110 || keyCode === 190;
- },
- isNumber(keyCode) {
- return (keyCode >= 48 && keyCode <= 57) || (keyCode >= 96 && keyCode <= 105);
- },
- },
- mounted() {
- if (this.type === 'number') {
- const inputEle = this.$refs.xinput.$refs.input;
- // eslint-disable-next-line
- inputEle.onkeydown = (e) = >{
- const keyCode = e.keyCode;
- if (!this.isBackspace(keyCode) && !this.isDot(keyCode) && !this.isNumber(keyCode)) {
- // 其他按键
- e.preventDefault();
- e.stopPropagation();
- return false;
- }
- };
- }
- }
- };
- </script>
View Code
来源: http://www.bubuko.com/infodetail-2448393.html