uni-车牌输入功能,类似与支付宝密码框
遇到这么一个需求:
车牌号输入,并且是每次输入后,每一位输入字符在占一个格子。
由于车牌号的构成对于密码而言比较复杂,否则可以模拟一个键盘,来控制和判断输入的内容,这样这个效果就比较简单。但是用于车牌输入的键盘内容比较多,所以这边用另外的方法。
首先创建一个input
<input :focus="bFocus" type="text" v-model="sCar" class="ipt-hide" @input="fInput" :maxlength="bIsUnit?7:8" @blur="fBlur" />
添加一些基础的事件,并且将其隐藏,隐藏样式比较特殊,可在文末全部代码处查看
然后创建方框等元素
<view class="car-item" v-for="nIndex in cCarNum" :class="{active:nIndex===sCar.length}" :key="nIndex"> {{sCar.split('')[nIndex]?sCar.split('')[nIndex].toUpperCase():''}} </view>
当点击方框时,输入框聚焦,然后输入的字符处理后挨个排放入框内。
但是这个完成后有个bug,
当输入字符后,经过多次修改,尤其是在请求之后,隐藏的输入框被聚焦时,光标会跳到最前,导致内容无法修改,或者输入的字符永远在已存在字符的前面。这种情况通过清空字符时解决不了的。
所以解决方案是在请求后重载组件,重载方法是在input上添加key,请求后改变key来实现组件重载
<comp-car @fCb="fCarIpt" ref="compcar" :key="nComp"></comp-car>
nComp: Math.random()
但是重载的方法在小程序上经过测试失效了,更改key并不能让组件重载,但是小程序内测试时也未出现该bug,所以小程序内就直接清空字符处理后不再进行更多操作;
组件的全部代码如下:
app:
<template> <view class="car" @tap="fFocus"> <input :focus="bFocus" type="text" v-model="sCar" class="ipt-hide" @input="fInput" :maxlength="bIsUnit?7:8" @blur="fBlur" /> <view class="car-item" v-for="nIndex in cCarNum" :class="{active:nIndex===sCar.length}" :key="nIndex"> {{sCar.split('')[nIndex]?sCar.split('')[nIndex].toUpperCase():''}} </view> <view class="car-item car-change" @tap.stop="fChange"><i class="iconfont"></i><text>{{bIsUnit?'新能源':'普通'}}</text></view> </view> </template> <script> export default { data() { return { sCar: '苏', bIsUnit: true, bFocus: false, cursor: 1 } }, computed: { cCarNum() { return this.bIsUnit ? [0, 1, 2, 3, 4, 5, 6] : [0, 1, 2, 3, 4, 5, 6, 7]; //车牌位数 } }, onLoad(option) { }, methods: { fClear() { this.sCar = '苏'; this.bIsUnit = true; this.bFocus = false; }, fChange() { this.sCar = '苏'; this.bFocus = false; this.bIsUnit = !this.bIsUnit; this.$emit('fCb', { sCar: this.sCar.toUpperCase(), bIsUnit: this.bIsUnit }) }, fBlur() { this.bFocus = false; }, fFocus() { this.bFocus = true; }, fInput() { this.$emit('fCb', { sCar: this.sCar.toUpperCase(), bIsUnit: this.bIsUnit }) } }, mounted() { this.fClear() } } </script> <style scoped lang="less"> .car { display: flex; flex-direction: row; justify-content: center; align-items: center; height: 44px; width: 100%; padding: 5px; box-sizing: border-box; } .car-item { height: 42px; width: 36px; margin: 0 2px; text-align: center; line-height: 42px; color: #3e3e3e; font-size: 18px; border: 1px solid #b2b2b2; border-radius: 3px; } .active { border-color: #19bbff; } .ipt-hide { position: absolute; z-index: -1; left: -100%; opacity: 0 } .car-change { display: flex; flex-direction: column; align-items: center; justify-content: center; border-style: dotted; font-size: 10px; line-height: 2; color: #7f7f7f; .iconfont { font-size: 10px; } } </style>
小程序内代码稍有改动,遍历渲染字符串时可以直接使用数字而不用数组
小程序代码:
<template> <view class="car" @tap="fFocus"> <input :focus="bFocus" type="text" v-model="sCar" class="ipt-hide" @input="fInput" :maxlength="cCarNum" @blur="fBlur" /> <view class="car-item" v-for="nIndex in cCarNum" :class="{active:nIndex===sCar.length-1}":key="nIndex"> {{sCar.split('')[nIndex]?sCar.split('')[nIndex].toUpperCase():''}} </view> <view class="car-item car-change" @tap.stop="fChange"><i class="iconfont"></i><text>{{bIsUnit?'新能源':'普通'}}</text></view> </view> </template> <script> export default { data() { return { sCar: '苏', bIsUnit: true, bFocus: false } }, computed: { cCarNum() { return this.bIsUnit ? 7 : 8; //车牌位数 } }, onLoad(option) { }, methods: { fClear() { this.sCar = '苏'; this.bIsUnit = true; this.bFocus = false; }, fChange() { this.sCar = '苏'; this.bFocus = false; this.bIsUnit = !this.bIsUnit; }, fBlur() { this.bFocus = false; }, fFocus() { this.bFocus = true; }, fInput() { this.$emit('fCb', { sCar: this.sCar.toUpperCase(), bIsUnit: this.bIsUnit }) } }, mounted() { this.fClear() } } </script> <style scoped lang="less"> .car { display: flex; flex-direction: row; justify-content: center; align-items: center; height: 42px; width: 100%; padding: 5px; box-sizing: border-box; } .car-item { height: 42px; width: 36px; margin: 0 2px; text-align: center; line-height: 42px; color: #3e3e3e; font-size: 18px; border: 1px solid #b2b2b2; border-radius: 3px; } .active { border-color: #19bbff; } .ipt-hide { position: absolute; z-index: -1; left: -100%; opacity: 0 } .car-change { display: flex; flex-direction: column; align-items: center; justify-content: center; border-style: dotted; font-size: 10px; line-height: 2; color: #7f7f7f; .iconfont { font-size: 10px; } } </style>