一、需求背景
在后台管理系统中,填写用户信息时,身份证号和出生年月是常见字段。
传统做法: 用户输入身份证号,再手动选择出生年月。
优化做法: 输入身份证号后,自动解析并填充出生年月,提升用户体验。
二、效果演示
用户输入:320106199001155647
↓
自动解析:第7-14位为出生年月 → 1990-01-15
↓
出生年月字段自动填充 → 用户无需再次选择
三、完整代码实现
1. 表单字段配置
javascript
// ===================== 身份证号 =====================
{
field: 'idCard',
label: '身份证号',
component: 'Input',
required: true,
colProps: col12Props,
componentProps: ({ formModel }) => ({
placeholder: '请输入身份证号',
maxlength: 18,
showCount: true,
onChange: (e) => {
const value = e.target.value;
// 身份证号合法且达到18位时,自动解析出生年月
if (value?.length === 18) {
const birthStr = value.slice(6, 14); // 取第7-14位
formModel.birthday = dayjs(birthStr).format('YYYY-MM');
}
},
}),
dynamicRules: () => [
{
required: true,
message: '请输入身份证号',
trigger: 'change',
},
{
pattern: idCardReg, // 身份证正则校验
message: '请输入正确的身份证号',
trigger: 'change',
},
],
},
// ===================== 出生年月 =====================
{
field: 'birthday',
label: '出生年月',
component: 'DatePicker',
required: true,
colProps: col12Props,
componentProps: {
placeholder: '请选择出生年月',
style: { width: '100%' },
format: 'YYYY-MM',
valueFormat: 'YYYY-MM',
// 禁止选择未来时间
disabledDate: (current) => {
return current && current > dayjs().endOf('day');
},
disabled: true, // 由身份证号自动填充,不允许手动编辑
},
},
四、核心知识点解析
1. 身份证号结构
| 位置 | 内容 | 示例 |
|---|---|---|
| 1-6位 | 行政区划代码 | 320106 |
| 7-14位 | 出生年月 | 19900115 |
| 15-17位 | 顺序码 | 547 |
| 18位 | 校验码 | 7 |
关键代码:
javascript
const birthStr = value.slice(6, 14); // 取出生日字符串
formModel.birthday = dayjs(birthStr).format('YYYY-MM'); // 格式化为 YYYY-MM
2. 为什么 birthday 要设置 disabled: true?
- ✅ 出生年月由身份证号自动计算得出,无需用户手动修改
- ✅ 防止用户手动修改导致数据不一致
- ✅ 表单逻辑更清晰
3. formModel 是什么?
formModel 是 VBen Admin 表单上下文对象,通过 componentProps 的函数参数传入,可以直接修改表单其他字段的值。
javascript
componentProps: ({ formModel }) => ({
// 直接赋值即可触发表单更新
onChange: (e) => {
formModel.birthday = '1990-01';
},
})
五、身份证号正则校验
javascript
// 身份证号校验正则(18位)
const idCardReg = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
校验规则说明
| 段 | 规则 |
|---|---|
| 1-6位 | [1-9] + 5位数字 |
| 7-14位 | 年月日合法格式 |
| 15-17位 | 3位数字 |
| 18位 | 数字或X/x |
六、完整代码(可直接复制使用)
javascript
import dayjs from 'dayjs';
// 身份证正则
const idCardReg = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
// 布局配置
const col12Props = { span: 12 };
// 身份证自动填充出生年月
const idCardField = {
field: 'idCard',
label: '身份证号',
component: 'Input',
required: true,
colProps: col12Props,
componentProps: ({ formModel }) => ({
placeholder: '请输入身份证号',
maxlength: 18,
showCount: true,
onChange: (e) => {
const value = e.target.value;
if (value?.length === 18) {
const birthStr = value.slice(6, 14);
formModel.birthday = dayjs(birthStr).format('YYYY-MM');
}
},
}),
dynamicRules: () => [
{ required: true, message: '请输入身份证号', trigger: 'change' },
{ pattern: idCardReg, message: '请输入正确的身份证号', trigger: 'change' },
],
};
const birthdayField = {
field: 'birthday',
label: '出生年月',
component: 'DatePicker',
required: true,
colProps: col12Props,
componentProps: {
placeholder: '请选择出生年月',
style: { width: '100%' },
format: 'YYYY-MM',
valueFormat: 'YYYY-MM',
disabledDate: (current) => current && current > dayjs().endOf('day'),
disabled: true,
},
};
七、注意事项
1. 为什么不用 trigger: 'blur'?
身份证号输入是连续的过程,用户还在输入时不应触发校验,所以使用 change 事件,在值变化时实时校验和解析。
2. 为什么出生年月字段设置为 disabled?
- 出生年月是派生字段,由身份证号计算得出
- 手动修改可能导致数据不一致
- 保持表单数据的一致性和完整性
3. 日期格式化
dayjs(birthStr) 传入 19900115 会自动解析为 1990-01-15,再 .format('YYYY-MM') 输出 1990-01。
八、扩展:15位身份证兼容
如果业务需要支持15位旧身份证:
javascript
componentProps: ({ formModel }) => ({
onChange: (e) => {
const value = e.target.value;
if (value?.length === 18) {
// 18位身份证
const birthStr = value.slice(6, 14);
formModel.birthday = dayjs(birthStr).format('YYYY-MM');
} else if (value?.length === 15) {
// 15位身份证(第7-12位为生日)
const birthStr = '19' + value.slice(6, 12);
formModel.birthday = dayjs(birthStr).format('YYYY-MM');
}
},
}),
九、总结
| 技巧 | 说明 |
|---|---|
formModel.xxx = value |
直接修改表单其他字段值 |
dayjs(str).format() |
字符串转日期格式化 |
slice(6, 14) |
从身份证号截取生日字段 |
disabled: true |
禁止手动编辑派生字段 |
value?.length === 18 |
判断身份证号长度再解析 |
核心就是:formModel 可以在任意字段的 onChange 中修改其他字段的值,实现联动效果。
📌 作者:只道寻常
💡 技巧:VBen Admin 表单联动,用
formModel就行!