项目场景:
在做uniapp的H5页面时,有个需求是要输入框要能支持可以保留两位小数输入,不能输入负数和其他字符。心想这简单,直接用uview的inputnumber组件这不就好了,结果测试提bug说不能输入小数点,我心想我的发,自己的不是可以吗,结果去试了一下,确实不能输入。ios里只能弹出自带的数字键盘,而且还是没有小数点的`
于是按照惯例,百度开发工程师开始了,开始百度搜索问题:搜到是说type不能为number,把number设置成digit就好了,官方图如下
嗯哼,改了之后,自己手机试了一下。不错,有效果,可以切换到其他输入法了,信心满满的把bug给点解决了,后来测试小姐姐又说这不行啊,我说怎么可能,为啥我滴可以,我看了之后确实不行,本地偶尔行。测试环境却不行
原因分析:
找了很久,发现其实就是ios没有对用户场景做比较全面的支持。于是一不做二不休,干脆自己做个组件算了,使用type=text,这下总不会限制键盘的方式了吧?
解决方案:
直接自己做一个组件,type=text,做个样式和uview的inputnumber组件一样的,vue代码如下
组件:
<template>
<view class="container">
<button @click="decrement" :disabled="isDisabled" class="btn no-space">-</button>
<input v-model="number" @input="handleInput" class="input" type="digit" step="0.01" />
<button @click="increment" class="btn">+</button>
</view>
</template>
<script>
export default {
props: {
value: {
type: Number,
default: 1,
},
},
data() {
return {
number: this.value,
isDisabled: this.value === 0,
};
},
watch: {
number(newVal) {
// 当 number 发生变化时,手动触发 v-model 绑定的更新
this.$emit("input", newVal);
}
},
methods: {
handleInput(event) {
// 获取用户输入的值
let inputValue = event.target.value;
// 移除非数字和小数点(禁止负数)
let cleanedInputValue = inputValue.replace(/[^0-9.]/g, '');
// 检查小数点的数量,保留一个小数点
const parts = cleanedInputValue.split('.');
// 限制整数部分最多五位数
if (parts[0].length > 5) {
parts[0] = parts[0].substring(0, 5);
}
// 限制小数部分最多两位数
if (parts.length > 1 && parts[1].length > 2) {
parts[1] = parts[1].substring(0, 2);
}
// 重新组合整数部分和小数部分
cleanedInputValue = parts.join('.');
// 将 cleanedInputValue 转换为浮点数
const numberValue = parseFloat(cleanedInputValue);
const formattedNumberValue = isNaN(numberValue) ? 0 : parseFloat(numberValue.toFixed(2));
// 更新组件数据
this.number = formattedNumberValue;
this.$emit("change", this.number);
},
canIncrement() {
return this.number < 99999;
},
canDecrement() {
return this.number > 0;
},
increment() {
if (this.canIncrement()) {
this.number = parseFloat(this.number || 0) + 0.01;
this.number = parseFloat(this.number.toFixed(2));
this.$emit("input", this.number);
}
},
decrement() {
if (this.canDecrement()) {
this.number = parseFloat(this.number - 0.01).toFixed(2);
this.$emit("input", this.number);
}
},
handleChange(e) {
this.$emit("change", { value: this.number || 0, index: '' });
this.isDisabled = parseFloat(e.target.value) === 0;
},
},
};
</script>
<style lang="scss" scoped>
.no-space {
letter-spacing: 0;
}
uni-button:after {
border: none !important;
}
.container {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.btn {
width: 60rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
border-radius: 8rpx 0 0 8rpx;
background: rgb(242, 243, 245);
height: 60rpx;
color: rgb(50, 50, 51);
}
.btn2 {
font-weight: bold;
font-size: 32rpx;
}
.input {
position: relative;
text-align: center;
padding: 0;
margin: 0 3px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
color: rgb(50, 50, 51);
font-size: 14px;
background: rgb(242, 243, 245);
height: 28px;
width: 42px;
}
</style>
使用方式:
<input-number v-model="list.time" @change="valChange"></input-number>
欧克欧克,完美解决问题。测试小姐姐说我不仅人长得帅,该bug也快