实现效果
![](https://i-blog.csdnimg.cn/direct/4eacabc9d6224c15bf1cae305b2e3f5e.png)
CommonLicenseNo 组件
<script setup lang="tsx" name="CommonLicenseNo">
import { ref } from "vue";
interface Props {
modelValue: string;
}
withDefaults(defineProps<Props>(), {
modelValue: ""
});
const area = [
"京",
"津",
"沪",
"渝",
"冀",
"豫",
"云",
"辽",
"黑",
"湘",
"皖",
"鲁",
"新",
"苏",
"浙",
"赣",
"鄂",
"桂",
"甘",
"晋",
"蒙",
"陕",
"吉",
"贵",
"粤",
"青",
"藏",
"川",
"宁",
"琼"
];
const areaLetter = [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0"
];
const carNo = ref("");
const emit = defineEmits<{
"update:modelValue": [value: any];
confirm: [];
}>();
// 选择车牌号
const selectCarNo = (item: any) => {
carNo.value = carNo.value + item;
emit("update:modelValue", carNo.value);
};
// 清除前一位
const back = () => {
if (carNo.value.length > 0) {
carNo.value = carNo.value.substring(0, carNo.value.length - 1);
emit("update:modelValue", carNo.value);
}
};
// 确认
const confirm = () => {
emit("confirm");
};
// 清除
const clear = () => {
carNo.value = "";
emit("update:modelValue", carNo.value);
};
// 更新
const updateValue = (licenseNo: any) => {
carNo.value = licenseNo;
emit("update:modelValue", carNo.value);
};
defineExpose({
updateValue
});
</script>
<template>
<div class="license_no_popover">
<div class="row_div">
<div class="every_div" v-for="item in area" :key="item">
<button @click="selectCarNo(item)">{{ item }}</button>
</div>
</div>
<div class="row_div">
<div class="every_div" v-for="item in areaLetter" :key="item">
<button @click="selectCarNo(item)">{{ item }}</button>
</div>
</div>
<div class="row_div">
<div class="btn_div">
<el-button type="primary" @click="back">
<el-icon><Back /></el-icon>
</el-button>
<el-button type="primary" @click="confirm">确认</el-button>
<el-button type="primary" @click="clear">清除</el-button>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.car_no_popover {
margin-top: 18px !important;
}
.every_div {
margin-top: 4px;
margin-left: 4px;
}
.every_div button {
width: 30px;
cursor: pointer;
}
.row_div {
display: flex;
flex-wrap: wrap;
}
.row_div .btn_div {
position: absolute;
right: 13px;
bottom: 11px;
}
.row_div .btn_div button {
height: 22px;
padding: 4px 13px;
}
</style>
调用组件
<template>
// ...
<el-col :span="6">
<el-form-item label="车牌号" prop="licenseNo">
<el-popover :visible="showPopover" placement="bottom" width="400">
<CommonLicenseNo ref="licenseNoRef" v-model="baseInfo.licenseNo" @confirm="showPopover = false" />
<template #reference>
<el-input
v-model.trim="baseInfo.licenseNo"
@click="showPopover = true"
@input="changeValue(baseInfo.licenseNo)"
placeholder="请输入车牌号"
/>
</template>
</el-popover>
</el-form-item>
</el-col>
// ...
</template>
<script setup lang="ts">
// ...
// 车牌号
const licenseNoRef = ref();
const showPopover = ref(false);
const changeValue = (licenseNo: any) => {
licenseNoRef.value.updateValue(licenseNo); // 调用子组件的方法
};
// ...
</script>
车牌号校验
// 车牌号校验
const validateLicenseNo = (errorMessage: string) => {
return (rule: any, value: any, callback: (error?: string | Error | undefined) => void) => {
let flag = false;
let creg =
/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
let xreg =
/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
if (value.length === 7) {
flag = creg.test(value);
} else if (value.length === 8) {
flag = xreg.test(value);
}
flag ? callback() : callback(new Error(errorMessage));
};
};
// 表单校验
const rules = ref<FormRules>({
licenseNo: [
{ required: true, message: "请输入车牌号", trigger: "change" },
{ validator: validateLicenseNo("请输入正确的车牌号"), required: true, trigger: "blur" }
],
});