背景:Vue开发移动端应用时,难免用到表单输入,比如金额。
需求:这时就需要吊起移动端数字键盘,input的type就必须设置成number,当然tel类型也可以,但是无法输入小数点。当然如果精力允许,你也可以自定义数字键盘是最好的,网上也有很多Vue数字键盘组件。
踩坑:一但用了input[type=number]类型有很多的坑。
- vue在申明表单model的时候必须是整形,要不然一堆红报错。
- maxlength属性不生效了,无法限制表单输入长度。
- 可以多次输入小数点,其实这个model已经变成空值了,这个是最坑的。
- 无法保留指定小数位数。
- 无法限制最大值,最小值。
思路一:用原生oninput函数实现输入正则替换,自定义函数替换字符。(会破坏vue统一性,不推荐)
思路二:用vue的@nput函数实现输入正则替换,自定义函数替换字符。(实现麻烦,不推荐)
思路三:用vue的变量监听函数。(输入某些值情况下不会被触发,不推荐)
<input class="amount-input" size="10" maxlength="6" type="number" placeholder="请输入金额" v-model.number="formData.amount">
watch:{
'formData.amount':function (newVal,oldVal) {
// 解决数字键盘可以输入输入多个小数点问题
if(newVal==='' && oldVal.toString().indexOf('.')>0){
this.formData.amount = oldVal;
return ;
}
// 保留两位小数
if(newVal){
newVal = newVal.toString();
var pointIndex = newVal.indexOf('.');
if(pointIndex>0 && (newVal.length - pointIndex)>3){
this.formData.amount = oldVal;
return ;
}
}
// 最大值
if(newVal>999999){
this.formData.amount = oldVal;
return ;
}
}
}
上面的方法解决了,可以多次输入小数点问题,和保留小数位数,还有限制大小都可以在这里实现,因为监听函数可以获取到历史输入值,很方便还原,不过在输入点的时候不会被触发,所以不是很理想。
思路四:用vue的computed函数,实现父组件和子组件双向通信。(为了方便大家使用我单独封装了一个插件MyNumberInput.vue,推荐,推荐,推荐,完美)
path:@/components/Plugin/Form/MyNumberInput.vue
<template>
<input class="my-number-input" type="number" :placeholder="placeholder" v-model.number="inputModel">
</template>
<script type="text/ecmascript-6">
export default {
components: {},
props: {
point:{
default: 0
},
max:Number,
placeholder:String,
value: {
default: null
},
},
computed:{
inputModel: {
get:function() {
// 父组件==>子组件 发消息
return this.value;
},
set:function (value) {
// 子组件==>父组件 发消息
let val = this.$el.value;
let len = val.length;
console.log(val);
// 解决首位直接输入 '0开头的数字'问题
if(len==2 && val.charAt(0)==0 && val.charAt(1)!='.'){
this.$el.value = val.charAt(1);
this.setParentModeVal(this.$el.value);
return;
}
// 解决数字键盘可以输入输入多个小数点问题
if(Math.abs(this.value) > 0 && val==='' && value ===''){
if(this.keyDownDel){
this.$el.value = '';// 正常删除
console.log('---正常删除---'+this.value);
}else {
this.$el.value = this.value;// 多次输入小数点时
console.log('---多次输入小数点---'+this.value);
}
this.setParentModeVal(this.$el.value);
return ;
}
// 解决开始就输入点问题
if(this.value === '' && val === '' && value === ''){
console.log('---22aa---'+this.value);
this.$el.value = '';
this.setParentModeVal('');
return ;
}
// 解决保留两位小数问题
if(val){
let pointIndex = val.indexOf('.');
if(this.point==0 && len==2 && val.charAt(pointIndex)=='.'){
console.log('只能输入整数');
this.$el.value = val.substr(0,pointIndex);
this.setParentModeVal(this.$el.value);
return ;
}
if(pointIndex>0 && (len - pointIndex)>(this.point+1)){
console.log('只能输入'+this.point+'位小数');
this.$el.value = val.substr(0,pointIndex + this.point +1);
this.setParentModeVal(this.$el.value);
return ;
}
}
// 解决输入最大值问题
if(this.max>0 && val>this.max){
console.log('---4---')
this.$el.value = val.substr(0,len-1);
this.setParentModeVal(this.$el.value);
return;
}
this.setParentModeVal(val);
return;
}
}
},
data() {
return {
keyDownDel:false,// 判断键盘输入值
}
},
mounted() {
// 判断键盘是否是删除动作
var that = this;
window.document.onkeydown = function(event){
let e = event || window.event || arguments.callee.caller.arguments[0];
if(e.keyCode==8||e.keyCode==46){
that.keyDownDel = true;
}else {
that.keyDownDel = false;
}
};
},
methods: {
setParentModeVal(value){
this.value = value;
this.$emit('input', value);
}
},
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.my-number-input{
//user-select: auto;
//border: 1px solid #ccc; // 去除默认未选中状态边框
//outline: none; // 去除默认选中状态边框
//background-color: rgba(0, 0, 0, 0);// 透明背景
//padding: 2px;
}
</style>
组件使用:
1. 导入:
import MyNumberInput from '@/components/Plugin/Form/MyNumberInput';
2. 注册:
export default {
components: {
MyNumberInput //注册
},
data() {
},
mounted() {
},
}
3. 视图:
<MyNumberInput :point="2" :max="99999" placeholder="请输入金额" v-model.number="formData.amount"></MyNumberInput>
属性说明:
- point 保留小数位数 ,默认0
- max 最大数,默认无限
- placeholder 输入提示 默认空
- v-model 绑定数据对象
解决问题:
- 解决首位直接输入 ‘0开头的数字’问题
- 解决数字键盘输入多个小数点问题
- 解决开始就输入点问题
- 解决保留两位小数问题
- 解决输入最大值问题
- 解决了默认弹出数字键盘问题