最近在uniapp项目中遇到使用车牌号键盘,主要的目的是用于车牌号的输入问题,直接看代码
以下代码可直接使用
一、组件代码:在项目中创建一个keyboard-input.vue文件
<template>
<view class="so-mask">
<view style="height: 100%" @tap="$emit('close')" />
<view class="so-plate animation-scale-up">
<view class="so-plate-head">
<view class="so-plate-type">
<radio-group @change="typeChange">
<label>
<radio value="1" :checked="type===1" />
普通车牌
</label>
<label>
<radio value="2" :checked="type===2" />
新能源车牌
</label>
</radio-group>
</view>
</view>
<view class="so-plate-body">
<view class="so-plate-word" :class="{ active: currentInputIndex == 0 }" @tap="inputSwitch"
data-index="0">
<text>{{ currentInputValue[0] }}</text>
</view>
<view class="so-plate-word" :class="{ active: currentInputIndex == 1 }" @tap="inputSwitch"
data-index="1">
<text>{{ currentInputValue[1] }}</text>
</view>
<view class="so-plate-dot"></view>
<view class="so-plate-word" :class="{ active: currentInputIndex == 2 }" @tap="inputSwitch"
data-index="2">
<text>{{ currentInputValue[2] }}</text>
</view>
<view class="so-plate-word" :class="{ active: currentInputIndex == 3 }" @tap="inputSwitch"
data-index="3">
<text>{{ currentInputValue[3] }}</text>
</view>
<view class="so-plate-word" :class="{ active: currentInputIndex == 4 }" @tap="inputSwitch"
data-index="4">
<text>{{ currentInputValue[4] }}</text>
</view>
<view class="so-plate-word" :class="{ active: currentInputIndex == 5 }" @tap="inputSwitch"
data-index="5">
<text>{{ currentInputValue[5] }}</text>
</view>
<view class="so-plate-word" :class="{ active: currentInputIndex == 6 }" @tap="inputSwitch"
data-index="6">
<text>{{ currentInputValue[6] }}</text>
</view>
<view class="so-plate-word" :class="{ active: currentInputIndex == 7 }" @tap="inputSwitch"
v-if="type == 2" data-index="7">
<text>{{ currentInputValue[7] }}</text>
</view>
</view>
<view class="so-plate-foot">
<view class="so-plate-keyboard" :style="{height:keyboardHeight}">
<view id="keyboard">
<block v-if="inputType == 1">
<view hover-class="hover" class="so-plate-key" v-for="el of provinceText" :key="el"
:data-value="el" @tap="chooseKey">{{ el }}</view>
</block>
<block v-if="inputType == 1">
<text class="so-plate-key fill-block"></text>
</block>
<block v-if="inputType >= 3">
<view hover-class="hover" class="so-plate-key" v-for="el of numberText" :key="el"
:data-value="el" @tap="chooseKey">{{ el }}</view>
</block>
<block v-if="inputType >= 2">
<view hover-class="hover" class="so-plate-key" v-for="el of wordText" :key="el"
:data-value="el" @tap="chooseKey">{{ el }}</view>
</block>
<block v-if="inputType == 3">
<text v-for="el of fillBlock" :key="el.num" class="so-plate-key fill-block"></text>
</block>
<block v-if="inputType == 4">
<view hover-class="hover" class="so-plate-key" v-for="el of lastWordText" :key="el"
:data-value="el" @tap="chooseKey">{{ el }}</view>
</block>
<text v-if="inputType == 4" class="so-plate-key fill-block"></text>
</view>
</view>
<view class="so-plate-btn-group">
<view>
<button class="so-plate-btn so-plate-btn--cancel" @tap="$emit('close')">取消</button>
</view>
<view>
<button class="so-plate-btn so-plate-btn--delete" @tap="deleteKey">删除</button>
<button class="so-plate-btn so-plate-btn--submit" @tap="exportPlate">完成</button>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'uni-plate-input',
data() {
return {
type: 1, //车牌类型
currentInputIndex: 0, //当前编辑的输入框
currentInputValue: ['', '', '', '', '', '', ''],
fillBlock: [{
num: 11
}, {
num: 12
}, {
num: 13
}, {
num: 14
}, {
num: 15
}, {
num: 16
}], //避免:key报错
keyboardHeightInit: false,
keyboardHeight: 'auto',
provinceText: [
'粤',
'京',
'冀',
'沪',
'津',
'晋',
'蒙',
'辽',
'吉',
'黑',
'苏',
'浙',
'皖',
'闽',
'赣',
'鲁',
'豫',
'鄂',
'湘',
'桂',
'琼',
'渝',
'川',
'贵',
'云',
'藏',
'陕',
'甘',
'青',
'宁',
'新'
],
numberText: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
wordText: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z'
],
lastWordText: ['挂', '港', '学', '领', '警']
};
},
props: {
plate: {
type: String
}
},
computed: {
//输入框类型
inputType() {
switch (this.currentInputIndex) {
case 0:
return 1;
break;
case 1:
return 2;
break;
case 2:
return 3;
break;
case 3:
return 3;
break;
case 4:
return 3;
break;
case 5:
return 3;
break;
case 6:
return this.type == 2 ? 3 : 4;
break;
case 7:
return 4;
break;
default:
return 1;
break;
}
}
},
watch: {
currentInputIndex: function(n, o) {
if (!this.keyboardHeightInit) return
this.$nextTick(() => {
this.changeKeyboardHeight()
})
}
},
methods: {
//车牌类型切换
typeChange(e) {
this.$emit("typeChange", e.detail.value);
const {
value
} = e.detail;
this.type = parseInt(value)
this.currentInputIndex = 0
if (value == 1) {
this.currentInputValue = ['', '', '', '', '', '', '']
} else {
this.currentInputValue = ['', '', '', '', '', '', '', '']
}
},
inputSwitch(e) {
const {
index
} = e.currentTarget.dataset;
this.currentInputIndex = parseInt(index);
},
chooseKey(e) {
const {
value
} = e.currentTarget.dataset;
this.$set(this.currentInputValue, this.currentInputIndex, value);
if (this.type == 1 && this.currentInputIndex < 6) {
this.currentInputIndex++
}
if (this.type == 2 && this.currentInputIndex < 7) {
this.currentInputIndex++
}
},
deleteKey() {
this.$set(this.currentInputValue, this.currentInputIndex, '')
if (this.currentInputIndex != 0) this.currentInputIndex--
},
exportPlate() {
const plate = this.currentInputValue.join('')
let err = false
if (this.type === 1 && plate.length != 7) {
err = true
} else if (this.type === 2 && plate.length != 8) {
err = true
}
if (err) return uni.showToast({
title: '请输入完整的车牌号码',
icon: 'none'
})
this.$emit('export', plate)
},
changeKeyboardHeight() {
const that = this
const query = uni.createSelectorQuery().in(this);
query.select('#keyboard').boundingClientRect();
query.exec(function(res) {
if (res && res[0]) {
that.keyboardHeight = res[0].height + uni.upx2px(30) + 'px'
that.keyboardHeightInit = true
}
});
}
},
mounted() {
// console.log(this.plate);
const plateKey = this.plate.split('')
if (plateKey.length === 7) {
this.type = 1
} else if (plateKey.length === 8) {
this.type = 2
}
if (plateKey.length === 7 || plateKey.length === 8) {
this.currentInputValue = plateKey
this.currentInputIndex = plateKey.length - 1
}
setTimeout(() => { //在动画结束之后才开始获取
this.$nextTick(() => {
this.changeKeyboardHeight()
})
}, 500);
}
};
</script>
<style scoped lang="less">
@import './uni-plate-input';
</style>
二、组件样式:同级创建一个uni-plate-input.less文件
.so-mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 998;
}
.so-plate {
box-sizing: border-box;
position: absolute;
bottom: 0;
width: 100%;
left: 0;
background: #fff;
padding: 25upx 25upx 0 25upx;
&-head {
display: flex;
justify-content: space-between;
align-items: center;
}
&-type {
flex:1;
display:block;
label {
display: inline-block;
min-height: 32upx;
font-size: 26upx;
margin-right: 10upx;
}
}
&-body {
box-sizing: border-box;
padding: 30upx 0;
display: flex;
justify-content: space-between;
align-items: center;
}
&-word {
border: 1upx solid #ccc;
border-radius: 10upx;
height: 0;
margin: 0 5upx;
box-sizing: border-box;
padding-bottom: calc((100% - 70upx) / 7);
width: calc((100% - 70upx) / 7);
position: relative;
&.active {
border-color: #007aff;
box-shadow: 0 0 15upx 0 #007aff;
}
text {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
font-weight: 700;
font-size: 32upx;
}
}
&-dot {
width: 15upx;
height: 15upx;
background: #ccc;
border-radius: 50%;
margin: 0 5upx;
}
&-keyboard {
background: #eee;
margin-left: -25upx;
margin-right: -25upx;
padding: 20upx 25upx 10upx 25upx;
box-sizing: border-box;
transition: all .3s;
&>view{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
}
&-key {
display: block;
background: #fff;
border-radius: 10upx;
box-shadow: 0 0 8upx 0 #bbb;
width: 80upx;
height: 80upx;
margin: 5upx 0;
font-size: 32upx;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
position: relative;
&.hover {
background: #efefef;
}
&.fill-block {
width: 80upx;
height: 80upx;
background: none;
box-shadow: none;
}
}
&-btn {
display: inline-block;
background: #fff;
border-radius: 10upx;
box-shadow: 0 0 10upx 0 #bbb;
font-size: 28upx;
text-align: center;
margin:0 0 0 10upx;
padding:0 25upx;
&-group{
display: flex;
justify-content: space-between;
background: #eee;
margin-left: -25upx;
margin-right: -25upx;
box-sizing: border-box;
padding: 0 25upx 10upx 25upx;
}
&--cancel{
margin:0;
}
&--submit{
background:#5773f9;
color:#fff;
}
&--delete{
color:#fd6b6d;
}
}
}
.animation-scale-up {
animation-duration: .2s;
animation-timing-function: ease-out;
animation-fill-mode: both;
animation-name: scale-up
}
@keyframes scale-up {
0% {
opacity: .8;
transform: scale(.8)
}
100% {
opacity: 1;
transform: scale(1)
}
}
三、使用
可以按需引入也可以在main.js中进行全局注册(不会自行百度)
①、自己项目中引入 import
//使用:@typeChange头部切换后子组件传递到父组件的(新能源和普通车牌之间的切换)
//v-if="bFocus"主要用于动态控制组件的显隐,通过点击事件改变bFocus的值
//@export="setPlate"组件完成按钮触发
//@close="bFocus = false"组件取消按钮控制显隐
//:plate="sCar"父组件传递给子组件的车牌号,用于默认车牌
<keyboard-input @typeChange="typeChange" v-if="bFocus" :plate="sCar" @export="setPlate"
@close="bFocus = false" />
//以下事件可自行打印查看methods中
typeChange(e){
},
setPlate(e){
},