因项目中有多处输入框要求只能输入整数或者浮点数, el-input 设置type=number 火狐浏览器这个属性是无效的; 所以就想到了 使用el-input type=text 输入的时候 正则匹配, 只能输入整数或者浮点数; 所以为了方便使用,需要对第三方库el-input 进行封装。
1. 初始封装的组件Number-input.vue 代码如下:
<template>
<el-input
:value="value"
v-bind="$attrs"
type="text"
@input="handleInput"
/>
</template>
<script>
import Big from 'big.js';
export default {
inheritAttrs: false,
props: {
value: {
type: String | Number,
default: ''
},
precision: {
type: Number,
validator(val) {
return val >= 0 && val === parseInt(val, 10);
}
},
minPrecision: {
type: Number,
validator(val) {
return val >= 0 && val === parseInt(val, 10);
}
},
maxPrecision: {
type: Number,
default: Infinity,
validator(val) {
return val >= 0 &&(val === parseInt(val, 10) || val === Infinity);
}
},
isNumber: {
type: Boolean,
default: false
},
max: {
type: String | Number,
default: Infinity
},
min: {
type: String | Number,
default: -Infinity
}
},
methods: {
handleInput(val) {
console.log('ssssss===', val)
let reg = ''
if(this.maxPrecision === Infinity) {
// this.$emit('input', val)
reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,20})?).*$`, 'g')
this.$emit('input', val.replace(reg ,'$1'))
} else if(this.maxPrecision >= 0) {
// 正则不能输入最大位数
reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,${this.maxPrecision}})?).*$`, 'g')
this.$emit('input', val.replace(reg ,'$1'))
}
val = val.replace(reg ,'$1')
this.$emit('input', val)
console.log('ssssss结束===', val)
},
handleInputChange(val) {
console.log('handleInputChange====', val, this.precision)
let newV = isNaN(val) ? '' : (val ? val.toString() : '')
if(newV) {
newV = this.getNewValue(val.toString())
}
this.$emit('input', newV)
},
getNewValue(val) {
// 根据精度获取幂次数, 获取精度整数位 利用math.round 四舍五入 转成float类型 再除以相同的10次幂 1.345直接利用tofixed(2) 取2位精度 会有问题
let newV = ''
let bigNewV = new Big(val)
let precisionArray = val.split('.')
let precision = precisionArray?.[1]?.length??0
if(this.minPrecision >= precision) {
newV = bigNewV.toFixed(this.minPrecision)
} else {
newV = bigNewV.toFixed(precision)
}
return newV
}
}
}
</script>
封装第三方组件主要用到 $atrrs 和 $listeners
v-bind="$attrs" v-on="$listeners"
$atrrs:接收父组件传过来的非class 和 style , 并且未在props 中注册使用的属性
$listeners :接收父组件传过来的非native 的事件
(注:.native 事件是父组件本身的事件, 在vue 中.native 只能用于组件上,.native 修饰符的作用是:在一个组件的根元素上直接监听一个原生事件; 原生的标签上不能使用 比如直接在<input @input.native='xxx' /> 会报错)
2. 父组件 Add.vue 中使用
<NumberInput
:maxPrecision="0"
v-model="quantity"
placeholder="请输入"
clearable />
上述使用目前为止都是正常的;
然后突然发现另外一个同事使用的时候 ,出现了问题!!!
在封装的组件Number-input.vue中多写一个属性为了接收父组件传过来的事件再传给下一级:v-on="$listeners"
<template>
<el-input
:value="value"
v-bind="$attrs"
v-on="$listeners"
type="text"
@input="handleInput"
/>
</template>
和上述对比 导致除了数字其他还能输入
原因就是 el-input 源码中 通过 v-on="$listeners" 接收了 业务组件Add.vue 传过来的事件, Add.vue 使用v-model 实现双向绑定, 默认有一个input 事件; 所以 当输入框输入数据的时候 , el-input 源码 中 触发input 事件, 同时向外触发 this.$emit('input', event.target.value) , 这个会先后触发Number-input.vue 和 Add.vue 中的 input事件; Add.vue中默认的input 事件接收的是 el-input 源码中传过来的原始值,会覆盖掉 Number-input.vue 中传过来的值, 最终v-model 中的值接收的也是el-input 源码中传过来的原始值.
el-input 源码
handleInput(event) {
// should not emit input during composition
// see: https://github.com/ElemeFE/element/issues/10516
if (this.isComposing) return;
// hack for https://github.com/ElemeFE/element/issues/8548
// should remove the following line when we don't support IE
if (event.target.value === this.nativeInputValue) return;
console.log('el-input input事件====', event)
this.$emit('input', event.target.value);
// ensure native input value is controlled
// see: https://github.com/ElemeFE/element/issues/12850
this.$nextTick(this.setNativeInputValue);
},
知道了原因所在,如何修复该问题:
1. Number-input 组件中的@input 和 @change事件 添加.native , 这样的话 el-input 源码中的 $emit('input' 就不会触发这两个事件 ; 这两个事件 会添加到 组件的根元素上 ; 看 el-input 源码可知 会添加到最外层的div 上; 然后 当我们输入数据的时候 ,首先$emit('input' 触发的是Add.vue 中的input 事件改变value 值;接着 通过冒泡 会触发父元素上的input 和 change事件, 在这 两个事件中 手动又去触发了 add.vue 中的input 事件(这个主要是自己怎么写), 改变了 value 值, 最终改了输入框的值文章来源:https://www.toymoban.com/news/detail-436664.html
2. Number-input.vue中监听value 值的变化 类似下面: 但是这种 不能 区分是input 还是change事件文章来源地址https://www.toymoban.com/news/detail-436664.html
watch: {
value: {
handler(val, oldV) {
let reg = ''
if(this.maxPrecision === Infinity) {
// this.$emit('input', val)
reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,20})?).*$`, 'g')
this.$emit('input', val.replace(reg ,'$1'))
} else if(this.maxPrecision >= 0) {
// 正则不能输入最大位数
reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,${this.maxPrecision}})?).*$`, 'g')
this.$emit('input', val.replace(reg ,'$1'))
}
val = val.replace(reg ,'$1')
this.$emit('input', val)
}
}
},
到了这里,关于element-ui :封装el-input 遇到的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!