Vue3 uniapp 微信小程序车牌号录入组件
car-plate-input
<template>
<view>
<view class="plate" >
<view class="item" :class="{ active: index === 0 }" @click="handleChange(0)">
{{ plateNum[0] }}
<text class="triangle"></text>
</view>
<view class="item" :class="{ active: index === 1 }" @click="handleChange(1)">{{ plateNum[1] }}</view>
<view class="point">●</view>
<view class="item" :class="{ active: index === 2 }" @click="handleChange(2)">{{ plateNum[2] }}</view>
<view class="item" :class="{ active: index === 3 }" @click="handleChange(3)">{{ plateNum[3] }}</view>
<view class="item" :class="{ active: index === 4 }" @click="handleChange(4)">{{ plateNum[4] }}</view>
<view class="item" :class="{ active: index === 5 }" @click="handleChange(5)">{{ plateNum[5] }}</view>
<view class="item" :class="{ active: index === 6 }" @click="handleChange(6)">{{ plateNum[6] }}</view>
<view class="item new-energy" :class="{ active: index === 7 }" @click="handleChange(7)">
<view v-if="plateNum[7] || plateNum[7] === 0">
<text>{{ plateNum[7] }}</text>
</view>
<uni-icons type="plusempty" size="13" color="#03BE9F" v-else></uni-icons>
</view>
</view>
<section class="panel" :class="{ show: show }">
<view class="header">
<view @click="handleReset">重置</view>
<view @click="show = false">完成</view>
</view>
<view class="panelList">
<view class="item" v-for="(item, idx) of currentDatas" :key="idx">
<view
v-if="item !== ''"
:class="{
disabled: (index == 1 && idx < 10) || (index > 1 && index < 6 && idx > 33),
}"
@click="handleClickKeyBoard(item, idx)"
>{{ item }}</view
>
</view>
<view class="item backspace" :class="{ special: index === 0 }" @click="handleDelete">×</view>
</view>
</section>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
plateNumber: {
type: Array,
default: Array.from(
{
length: 8,
},
v => ''
),
},
})
const emits = defineEmits(['PlateChange'])
const plateNum = ref(props.plateNumber)
const show = ref(false)
const index = ref(-1)
const areaDatas = [
'京',
'津',
'渝',
'沪',
'冀',
'晋',
'辽',
'吉',
'黑',
'苏',
'浙',
'皖',
'闽',
'赣',
'鲁',
'豫',
'鄂',
'湘',
'粤',
'琼',
'川',
'贵',
'云',
'陕',
'甘',
'青',
'蒙',
'桂',
'宁',
'新',
'藏',
'使',
'领',
'',
'',
'',
'',
'',
'',
]
const characterDatas = [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'J',
'K',
'L',
'M',
'N',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'挂',
'警',
'学',
'港',
'澳',
]
const currentDatas = computed(() => {
return index.value === 0 ? areaDatas : characterDatas
})
const handleChange = idx => {
index.value = idx
show.value = true
}
const handleClickKeyBoard = (item, idx) => {
if ((index.value === 1 && idx < 10) || (index.value > 1 && index.value < 6 && idx > 33)) {
return
}
if (index.value < 8) {
plateNum.value[index.value] = item
emits('PlateChange', plateNum.value)
}
if (index.value < 7) {
index.value++
}
}
// 重置
const handleReset = () => {
index.value = 0
for (let i = 0; i < 8; i++) {
plateNum.value[i] = ''
}
emits('PlateChange', plateNum.value)
}
// 删除
const handleDelete = () => {
plateNum.value[index.value] = ''
emits('PlateChange', plateNum.value)
if (index.value > 0) {
index.value--
}
}
</script>
<style scoped lang="less">
.plate {
display: flex;
justify-content: space-between;
padding-left: 10rpx;
padding-right: 10rpx;
.item {
width: 64rpx;
height: 80rpx;
background-color: #f3f4f7;
border-radius: 8rpx;
text-align: center;
line-height: 80rpx;
font-size: 32rpx;
color: rgba(0, 0, 0, 0.9);
font-weight: bold;
position: relative;
border: 2rpx solid rgba(207, 214, 230, 1);
&.active {
background-color: #bbbbbb;
}
}
.new-energy {
box-sizing: border-box;
border: 2rpx dashed #03be9f;
font-weight: bold;
uni-icons {
display: flex;
align-items: center;
justify-content: center;
}
}
.point {
height: 80rpx;
text-align: center;
line-height: 80rpx;
color: #bdc4cc;
font-size: 18rpx;
}
.triangle {
width: 0;
height: 0;
border: 6rpx solid transparent;
border-right-color: #00c69d;
border-bottom-color: #00c69d;
border-radius: 1rpx 2rpx 1rpx;
position: absolute;
right: 6rpx;
bottom: 6rpx;
}
}
.panel {
position: fixed;
left: 0;
width: 100%;
bottom: 0;
z-index: 999;
box-sizing: border-box;
background-color: #f5f5f5;
transition: all 0.3s ease;
transform: translateY(100%);
&.show {
transform: translateX(0);
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
height: 96rpx;
color: #2080f7;
font-size: 34rpx;
}
.panelList {
padding: 0 19rpx 20rpx;
.item {
display: inline-block;
width: calc(~'(100% - 72rpx) / 10');
height: 84rpx;
margin-right: 8rpx;
margin-bottom: 8rpx;
vertical-align: top;
view {
width: 100%;
height: 84rpx;
line-height: 84rpx;
border-radius: 6rpx;
background: #fefffe;
font-size: 32rpx;
color: rgba(0, 0, 0, 0.9);
font-weight: bold;
text-align: center;
&.disabled {
background-color: rgba(254, 255, 254, 0.6);
color: rgba(0, 0, 0, 0.23);
}
}
&:nth-of-type(10n) {
margin-right: 0;
}
}
.backspace {
vertical-align: top;
font-size: 48rpx;
font-weight: bold;
text-align: center;
height: 84rpx;
line-height: 84rpx;
border-radius: 6rpx;
background: #fefffe;
color: rgba(0, 0, 0, 0.9);
}
}
}
</style>
Parent.vue 中使用
<template>
<view class="page">
<cus-nav background="rgba(255, 255, 255, 1)"></nh-nav>
<view class="container">
<view class="car">
<view class="title"> 车牌号码<text class="icon">*</text> </view>
<car-plate-input :plateNumber="plateNumber" @PlateChange="handleNumChange"></nh-car-plate-input>
<view class="btn-wrapper">
<button class="btn" @click="cancel">取消</nh-button>
<button class="btn" @click="handleSave">保存</nh-button>
</view>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const plateNumber = ref(['', '', '', '', '', '', '', ''])
const handleNumChange = (val: string[]) => {
plateNumber.value = val
}
const cancel = () => {}
const handleSave = () => {}
</script>
<style lang="less" scoped>
.page{
position: relative;
height: 100vh;
background-color: #f5f5f5;
}
.car {
width: calc(~'100% - 60rpx');
height: 662rpx;
margin: 16rpx auto;
background-color: #ffffff;
box-shadow: 0 4rpx 20rpx 0 rgba(101, 108, 106, 0.1);
border-radius: 16rpx;
padding: 0 32rpx;
box-sizing: border-box;
position: relative;
.title {
height: 104rpx;
line-height: 104rpx;
font-size: 28rpx;
color: rgba(102, 110, 128, 1);
.icon {
font-size: 32rpx;
color: #fa3239;
vertical-align: middle;
margin-left: 4rpx;
}
}
.btn-wrapper {
position: absolute;
display: flex;
margin-top: 96rpx;
bottom: 48rpx;
width: calc(~'100% - 64rpx');
.btn {
width: 50%;
line-height: 96rpx;
border-radius: 16rpx;
color: #ffffff;
font-size: 28rpx;
padding: 0 10rpx;
}
}
}
</style>
根据此vue2组件改写而来 (uni-app 车牌录入组件封装(支持新能源))