UniApp车牌号输入组件封装摘要: 该组件提供标准化的车牌号输入功能,支持普通车牌和新能源车牌两种类型切换。主要特性包括: 智能键盘:自动切换省份、字母和数字键盘 新能源车牌支持:自动适配9位车牌格式 交互体验:点击车牌位自动弹出对应键盘 双向绑定:支持v-model绑定车牌值 可配置性:可设置初始车牌类型和是否显示类型选择器 组件采用Vue单文件组件形式开发,包含完整的模板、脚本和样式,可直接在UniApp项目中引用。通过watch监听value变化实现双向绑定,提供plate-type-change事
车牌号输入功能标准的uniapp组件形式,方便在项目中调用:
<!-- components/LicensePlateInput.vue -->
<template>
<view class="license-plate-input">
<!-- 车牌类型选择 -->
<view class="plate-type-selector" v-if="showTypeSelector">
<view
class="type-item"
:class="{ active: plateType === 'normal' }"
@tap="switchPlateType('normal')"
>
普通车牌
</view>
<view
class="type-item"
:class="{ active: plateType === 'newEnergy' }"
@tap="switchPlateType('newEnergy')"
>
新能源车牌
</view>
</view>
<!-- 车牌显示区域 -->
<view class="plate-display" :class="plateType">
<view
class="plate-item"
:class="{ 'plate-item-active': index === activeIndex }"
v-for="(item, index) in displayPlateArray"
:key="index"
@tap="focusInput(index)"
>
{{ item || '' }}
</view>
</view>
<!-- 键盘容器 -->
<u-popup v-model="showKeyboard" mode="bottom" border-radius="20">
<view class="keyboard-container">
<view class="keyboard-header">
<text class="keyboard-title">{{ getKeyboardTitle() }}</text>
<u-icon name="close" @click="showKeyboard = false"></u-icon>
</view>
<view class="keyboard-keys">
<view
class="key-item"
v-for="(key, index) in currentKeys"
:key="index"
@tap="selectKey(key)"
>
{{ key }}
</view>
<view
class="key-item key-delete"
@tap="deleteKey"
v-if="keyboardType !== 'province'"
>
删除
</view>
</view>
<view class="keyboard-toggle" v-if="keyboardType !== 'province' && plateType === 'normal'">
<view
class="toggle-btn"
:class="{ 'active': keyboardType === 'alphabet' }"
@tap="switchKeyboard('alphabet')"
>
ABC
</view>
<view
class="toggle-btn"
:class="{ 'active': keyboardType === 'number' }"
@tap="switchKeyboard('number')"
>
123
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
name: 'LicensePlateInput',
props: {
// 初始车牌类型
initPlateType: {
type: String,
default: 'normal' // normal 或 newEnergy
},
// 是否显示车牌类型选择器
showTypeSelector: {
type: Boolean,
default: true
},
// 初始车牌号码
value: {
type: String,
default: ''
}
},
data() {
return {
plateType: this.initPlateType,
plateArray: new Array(8).fill(''),
newEnergyPlateArray: new Array(9).fill(''),
activeIndex: 0,
showKeyboard: false,
keyboardType: 'province' // province, alphabet, number
}
},
computed: {
provinceKeys() {
return [
'京', '津', '冀', '晋', '蒙', '辽', '吉', '黑', '沪', '苏',
'浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '粤', '桂',
'琼', '渝', '川', '贵', '云', '藏', '陕', '甘', '青', '宁',
'新', '港', '澳', '台', '使', '领', '警', '学', '试'
]
},
alphabetKeys() {
return [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z'
]
},
numberKeys() {
return [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
]
},
newEnergyKeys() {
return [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'
]
},
currentKeys() {
// 新能源车牌特殊处理
if (this.plateType === 'newEnergy') {
// 新能源车牌最后一位只能是数字或特定字母
if (this.activeIndex === 8) {
return this.newEnergyKeys;
}
}
switch(this.keyboardType) {
case 'province':
return this.provinceKeys;
case 'alphabet':
return this.alphabetKeys;
case 'number':
return this.numberKeys;
default:
return this.provinceKeys;
}
},
displayPlateArray() {
return this.plateType === 'newEnergy' ? this.newEnergyPlateArray : this.plateArray;
}
},
watch: {
value: {
handler(newVal) {
if (newVal) {
this.setPlateNumber(newVal);
}
},
immediate: true
}
},
methods: {
switchPlateType(type) {
this.plateType = type;
this.activeIndex = 0;
this.showKeyboard = false;
this.$emit('plate-type-change', type);
},
focusInput(index) {
this.activeIndex = index;
this.showKeyboard = true;
// 根据车牌类型和位置确定键盘类型
if (this.plateType === 'normal') {
if (index === 0) {
this.keyboardType = 'province';
} else if (index === 1) {
this.keyboardType = 'alphabet';
} else {
this.keyboardType = 'number';
}
} else {
// 新能源车牌
if (index === 0) {
this.keyboardType = 'province';
} else if (index === 1) {
this.keyboardType = 'alphabet';
} else if (index >= 2 && index <= 7) {
this.keyboardType = 'number';
} else if (index === 8) {
// 新能源最后一位可以是数字或特定字母
this.keyboardType = 'number';
}
}
},
selectKey(key) {
// 设置当前位的值
if (this.plateType === 'newEnergy') {
this.$set(this.newEnergyPlateArray, this.activeIndex, key);
} else {
this.$set(this.plateArray, this.activeIndex, key);
}
// 自动跳转到下一位
const maxIndex = this.plateType === 'newEnergy' ? 8 : 7;
if (this.activeIndex < maxIndex) {
this.activeIndex++;
// 根据车牌类型和位置自动切换键盘类型
if (this.plateType === 'normal') {
if (this.activeIndex === 1) {
this.keyboardType = 'alphabet';
} else {
this.keyboardType = 'number';
}
} else {
// 新能源车牌
if (this.activeIndex === 1) {
this.keyboardType = 'alphabet';
} else if (this.activeIndex >= 2 && this.activeIndex <= 7) {
this.keyboardType = 'number';
} else if (this.activeIndex === 8) {
this.keyboardType = 'number';
}
}
} else {
// 最后一位输入完成后隐藏键盘
this.showKeyboard = false;
}
// 触发输入事件
this.$emit('input', this.getPlateNumber());
},
deleteKey() {
if (this.activeIndex > 0) {
// 清空当前位
if (this.plateType === 'newEnergy') {
this.$set(this.newEnergyPlateArray, this.activeIndex, '');
} else {
this.$set(this.plateArray, this.activeIndex, '');
}
// 如果当前位已空,则跳转到上一位
if (this.getCurrentPlateArray()[this.activeIndex] === '') {
this.activeIndex--;
}
} else {
// 第一位时直接清空
if (this.plateType === 'newEnergy') {
this.$set(this.newEnergyPlateArray, this.activeIndex, '');
} else {
this.$set(this.plateArray, this.activeIndex, '');
}
}
// 触发输入事件
this.$emit('input', this.getPlateNumber());
},
switchKeyboard(type) {
this.keyboardType = type;
},
getKeyboardTitle() {
if (this.plateType === 'newEnergy' && this.activeIndex === 8) {
return '选择数字或字母(A-F)';
}
switch(this.keyboardType) {
case 'province':
return '选择省份';
case 'alphabet':
return '选择字母';
case 'number':
return '选择数字';
default:
return '选择字符';
}
},
getCurrentPlateArray() {
return this.plateType === 'newEnergy' ? this.newEnergyPlateArray : this.plateArray;
},
getPlateNumber() {
const plateArray = this.plateType === 'newEnergy' ? this.newEnergyPlateArray : this.plateArray;
return plateArray.join('');
},
// 设置车牌号码
setPlateNumber(plateNumber) {
if (!plateNumber) return;
const len = plateNumber.length;
if (len === 8) {
this.plateType = 'normal';
for (let i = 0; i < 8; i++) {
this.$set(this.plateArray, i, plateNumber[i] || '');
}
} else if (len === 9) {
this.plateType = 'newEnergy';
for (let i = 0; i < 9; i++) {
this.$set(this.newEnergyPlateArray, i, plateNumber[i] || '');
}
}
},
// 清空车牌号码
clearPlate() {
this.plateArray = new Array(8).fill('');
this.newEnergyPlateArray = new Array(9).fill('');
this.activeIndex = 0;
this.$emit('input', '');
}
}
}
</script>
<style lang="scss" scoped>
.license-plate-input {
padding: 20rpx;
}
.plate-type-selector {
display: flex;
justify-content: center;
margin-bottom: 30rpx;
}
.type-item {
padding: 15rpx 30rpx;
border: 2rpx solid #ddd;
border-radius: 50rpx;
margin: 0 20rpx;
font-size: 28rpx;
&.active {
background-color: #2979ff;
color: #fff;
border-color: #2979ff;
}
}
.plate-display {
display: flex;
justify-content: center;
margin-bottom: 40rpx;
&.normal .plate-item {
width: 60rpx;
}
&.newEnergy .plate-item {
width: 55rpx;
}
}
.plate-item {
height: 100rpx;
border: 2rpx solid #ddd;
display: flex;
align-items: center;
justify-content: center;
font-size: 36rpx;
font-weight: bold;
margin: 0 5rpx;
border-radius: 8rpx;
&.plate-item-active {
border-color: #2979ff;
box-shadow: 0 0 10rpx rgba(41, 121, 255, 0.3);
}
}
.keyboard-container {
background-color: #f5f5f5;
padding: 20rpx;
}
.keyboard-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 2rpx solid #eee;
}
.keyboard-title {
font-size: 32rpx;
font-weight: bold;
}
.keyboard-keys {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
padding: 20rpx 0;
max-height: 500rpx;
overflow-y: auto;
}
.key-item {
width: calc(10% - 10rpx);
height: 70rpx;
background-color: #fff;
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
margin: 10rpx 5rpx;
font-size: 32rpx;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
&.key-delete {
background-color: #ff5a5f;
color: #fff;
width: 15%;
}
}
.keyboard-toggle {
display: flex;
justify-content: center;
padding: 20rpx 0;
}
.toggle-btn {
padding: 10rpx 30rpx;
background-color: #e0e0e0;
border-radius: 30rpx;
margin: 0 20rpx;
font-size: 28rpx;
&.active {
background-color: #2979ff;
color: #fff;
}
}
</style>
使用示例:
<!-- pages/example/example.vue -->
<template>
<view class="container">
<view class="title">车牌号输入示例</view>
<!-- 基础用法 -->
<view class="section">
<view class="section-title">基础用法</view>
<LicensePlateInput
v-model="plateNumber"
@plate-type-change="onPlateTypeChange"
/>
<view class="result">输入的车牌号: {{ plateNumber }}</view>
</view>
<!-- 指定初始车牌类型 -->
<view class="section">
<view class="section-title">新能源车牌</view>
<LicensePlateInput
v-model="newEnergyPlate"
init-plate-type="newEnergy"
/>
<view class="result">输入的车牌号: {{ newEnergyPlate }}</view>
</view>
<!-- 隐藏类型选择器 -->
<view class="section">
<view class="section-title">隐藏类型选择器</view>
<LicensePlateInput
v-model="fixedPlate"
:show-type-selector="false"
init-plate-type="normal"
/>
<view class="result">输入的车牌号: {{ fixedPlate }}</view>
</view>
<!-- 操作按钮 -->
<view class="actions">
<u-button @click="clearAll">清空所有</u-button>
<u-button @click="setPlate">设置车牌号</u-button>
</view>
</view>
</template>
<script>
import LicensePlateInput from '@/components/LicensePlateInput.vue'
export default {
components: {
LicensePlateInput
},
data() {
return {
plateNumber: '',
newEnergyPlate: '',
fixedPlate: ''
}
},
methods: {
onPlateTypeChange(type) {
console.log('车牌类型切换为:', type)
},
clearAll() {
this.plateNumber = ''
this.newEnergyPlate = ''
this.fixedPlate = ''
},
setPlate() {
this.plateNumber = '京A12345'
this.newEnergyPlate = '京AD123456'
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 20rpx;
}
.title {
text-align: center;
font-size: 36rpx;
font-weight: bold;
margin-bottom: 40rpx;
}
.section {
margin-bottom: 40rpx;
padding: 20rpx;
background-color: #f8f8f8;
border-radius: 10rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
}
.result {
margin-top: 20rpx;
padding: 20rpx;
background-color: #fff;
border-radius: 10rpx;
}
.actions {
display: flex;
justify-content: space-around;
margin-top: 40rpx;
}
</style>
组件特性
Props
initPlateType: 初始车牌类型 (‘normal’ | ‘newEnergy’),默认 ‘normal’showTypeSelector: 是否显示车牌类型选择器 (Boolean),默认 truevalue: 初始车牌号码 (String),默认 ‘’
Events
input: 车牌号码变化时触发,返回完整车牌号plate-type-change: 车牌类型切换时触发,返回类型值
Methods
getPlateNumber(): 获取当前车牌号码setPlateNumber(plateNumber): 设置车牌号码clearPlate(): 清空车牌号码
使用方式
- 将组件文件保存到
components/LicensePlateInput.vue - 在页面中引入并注册组件
- 使用
v-model进行双向绑定 - 可通过
init-plate-type指定初始车牌类型 - 可通过
show-type-selector控制是否显示类型选择器
这样就完成了一个功能完整的uniapp车牌号输入组件,可以直接在项目中使用。
140

被折叠的 条评论
为什么被折叠?



