ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Element必填星号不显示?表单校验规则与prop配置详解

Element必填星号不显示?表单校验规则与prop配置详解 1. 为什么表单校验总在必填这一关翻车做过后台管理系统的前端十有八九都被必填校验折腾过。不是字段没配规则而是用户根本不知道这个字段要填——等提交的时候被拦截弹出一串红字体验已经扣分了。真正友好的做法是一开始就让用户看到哪些是必填项这就是Element表单里那个红色*星号存在的意义。先说一个最基础的场景el-form配合el-form-item不给任何额外配置表单长这样el-form :modelformData el-form-item label用户名 el-input v-modelformData.username / /el-form-item /el-form这时候label前面是没有星号的。很多人第一反应是在label文字前面手动加一个红色的*能实现但非常蠢——不同浏览器、不同字体渲染下对不齐而且一旦做国际化或者label从接口动态返回星号位置和颜色就全乱了。正确姿势是利用Element的校验规则自动生成星号规则到位星号自己就出来了。这篇内容主要面向三类读者刚接触VueElement的初级前端正在从能用向好用打磨表单的中级开发者以及需要维护老项目但一直被必填校验搞到头大的同学。我会把Element必填星号的触发逻辑、常见配置场景、动态切换的坑以及Form组件的隐藏技能一次性讲透。2. Element星号触发机制三条规则缺一不可Element的必填星号不是靠CSS硬画出来的它跟el-form-item的校验状态深度绑定。你要理解这背后的触发条件后面遇到星号不显示星号显示了但校验不生效这类问题才能一眼定位。2.1 完整版配置rule、prop、required三件套先看一个能正常显示星号的经典写法el-form :modelformData :rulesrules refformRef el-form-item label用户名 propusername required el-input v-modelformData.username / /el-form-item /el-formrules: { username: [ { required: true, message: 请输入用户名, trigger: blur } ] }这里有三样东西缺一不可propusername告诉表单这个字段对应formData里的哪个key也是校验规则匹配的索引required属性直接绑在el-form-item上等价于给校验规则加一条required: truerules里的required: true真正的校验逻辑在这里message是校验失败时的提示文案trigger决定了什么时候触发校验blur就是失焦时很多人会有个误解以为required属性会调用labellabel有了就出星号。实际上el-form-item的required属性会同时做两件事——一是把required状态传给校验规则二是控制label前面星号的显示。但要注意如果只写required而不写prop星号能出来校验却不会触发。因为Element的校验器要通过prop找到具体字段没有prop规则再全也是空中楼阁。2.2 极简版只用required属性如果表单比较简单不想单独维护rules对象可以直接只写requiredel-form-item label邮箱 propemail required el-input v-modelformData.email / /el-form-item这时候Element内部会默认生成一条校验规则星号显示提交时也校验虽然message是内置的默认文案。够用但不推荐在生产环境这么用——你无法定制提示语而且有些自定义组件比如日期选择器在required状态下对空值的判断逻辑会有差异后面我们会细说。2.3 星号不显示的排查顺序如果你遇到规则配了required也写了星号就是不出来的情况按这个顺序排查el-form有没有写:modelformData没有model整个表单的校验体系都不会工作el-form-item有没有写prop没有prop规则匹配不到字段rules里的key和prop是否一致注意是字符串完全一致大小写、拼写有一个不对都不行el-form-item的required属性是不是不小心绑成了false比如requiredfalse这种字符串写法在Vue里其实是true因为非空字符串永远是真值第4点很阴险我在老项目里见过不止一次。requiredfalse写出来星号照样显示因为字符串false转成布尔值是true。如果一定要动态控制必填与否下面会专门讲。3. 必填星号的四种实战场景从静态到动态光会基础写法还不够真实项目里表单形态千奇百怪。我按从简单到复杂整理了几种高频场景每种都给出可复制的完整代码。3.1 场景A带红点提示的隐藏label有些表单为了紧凑label是不显示的只显示占位符placeholder。这样的表单更需要必填提示不然用户根本不知道要填什么。但星号挂在label上label都不见了星号自然也消失。解决办法是用CSS把label隐藏但不移除DOMel-form-item propphone required el-input v-modelformData.phone placeholder请输入手机号 / /el-form-item/* 隐藏label文字但保留必填星号的渲染空间 */ .el-form-item__label { width: 0 !important; padding: 0 !important; overflow: hidden; white-space: nowrap; }实测下来这样处理星号依然会渲染在label区域配合position: relative微调对齐即可。比在placeholder前面加*高明得多因为真正参与校验的required属性没有被动过。3.2 场景B动态表单的必填切换表单里常有是否开具发票这种开关开了发票发票抬头、税号必填关了发票这些字段整个隐藏。星号必须跟着表单状态变el-form-item label发票抬头 propinvoiceTitle :requiredformData.needInvoice el-input v-modelformData.invoiceTitle :disabled!formData.needInvoice / /el-form-itemrules: { invoiceTitle: [ { required: true, message: 请输入发票抬头, trigger: blur } ] }这里有个坑rules里required: true是写死的但表单的required属性是动态的。当needInvoice为false时星号确实消失了但校验规则里依然是required: true提交时照样拦截。正确的做法是用函数校验动态判断rules: { invoiceTitle: [ { validator: (rule, value, callback) { if (formData.needInvoice !value) { callback(new Error(请输入发票抬头)) } else { callback() } }, trigger: blur } ] }一句话总结星号显示用:required动态控制校验是否生效用validator函数动态控制两者要配合只改一个必然出问题。3.3 场景C包含自定义组件的必填校验日期选择器、级联选择器、上传组件这类自定义组件v-model绑定的值类型不是普通字符串直接套用required: true的字符串校验经常会出现明明选择了日期却还是提示必填的怪事。以日期范围选择器为例el-form-item label活动时间 propactiveTime required el-date-picker v-modelformData.activeTime typedaterange value-formatYYYY-MM-DD start-placeholder开始日期 end-placeholder结束日期 / /el-form-itemrules: { activeTime: [ { type: array, required: true, message: 请选择活动时间, trigger: change } ] }注意这里的type: array——daterange绑定的值是数组不声明类型Element会按字符串去判空数组在非空判断上很容易出现误判。上传组件则要声明type: array并校验数组长度。3.4 场景D表格行内表单的必填后台系统常见表格行内直接编辑的需求每行都有几个必填输入框。这种场景不能把rules挂在整表上因为每行的数据对象是循环出来的。处理方式是给el-form的rules做成方法每行单独校验el-form v-for(row, index) in tableData :keyindex :modelrow :rulesgetRowRules(row) refrowForms el-form-item label数量 :propquantity required el-input v-modelrow.quantity / /el-form-item /el-formgetRowRules(row) { return { quantity: [ { required: true, message: 请输入数量, trigger: blur } ] } }注意:modelrow而不是:modeltableData[index]。虽然引用指向的对象是同一个但模板中直接写tableData[index]当表格数据顺序变化时可能绑定到错误的行。用循环变量row更直觉也更安全。4. 星号样式定制不满足于默认红色Element的默认星号是红色够醒目但有时候设计稿要求星号颜色、大小、位置都要调整。比如某些内部系统里必填星号是橙色因为设计规范里红色要留给错误提示。样式覆盖的思路有三层。4.1 改颜色和大小/* 全局覆盖所有必填星号变橙色 */ .el-form-item.is-required .el-form-item__label::before { color: #ff9500; font-size: 16px; }这个选择器的关键在于is-required类名——Element在el-form-item有required属性或者校验规则为必填时会自动加这个类。直接用::before伪元素覆盖默认样式。4.2 默认星号位置调整Element星号默认是margin-right: 4px在label文字正前方。有些设计稿喜欢星号靠右对齐可以改成absolute定位.el-form-item.is-required .el-form-item__label::before { position: absolute; left: -10px; }注意这时候要给.el-form-item__label加上position: relative否则星号会跑出label区域。4.3 自定义必填提示文字替代星号还有个冷门需求星号换成必填两个字。直接改伪元素内容.el-form-item.is-required .el-form-item__label::before { content: 必填; color: #ff9500; font-size: 12px; margin-right: 4px; }实测这种样式在大屏展示场景挺受欢迎必填比的引导性更强尤其面向不熟悉表单习惯的C端用户。但要注意content替换后默认的星号就被完全覆盖了不会出现一个必填加一个的重复。5. 隐藏技能el-form的很多不为认知的能力就藏在scoped验证里skill重灾区很多人把表单校验局限在提交时validate一下其实Element Form的校验机制远比你想象得灵活。下面这三个用法是我在实际项目里频繁用到、但网上很少被系统讲清楚的。5.1 只校验某几个字段提交时不是所有字段都要校验。比如保存草稿只需要校验标题提交需要校验全部必填项。用validateField精确控制// 只校验title和content两个字段 this.$refs.formRef.validateField([title, content], (errorMessage) { if (errorMessage) { // 有字段未通过校验 return } // 通过执行下一步 })这个方法返回一个Promise可以配合await第二个参数是回调。如果只传一个字段名用字符串传数组则校验多个字段。实测在分步表单里非常实用——第一步只校验第一屏的字段不必让用户被迫填完所有内容才能继续。5.2 校验之前先清空上一次的校验状态表单在编辑状态下用户改了某个字段之后保存前可能希望所有旧的校验红字都消失。这时用clearValidatethis.$refs.formRef.clearValidate([username, email])不传参数就是清空整个表单的校验状态。注意它只是清除红字和错误提示不会改变数据内容也不会触发重新校验。这个API在切换编辑对象时几乎是必用的——否则上一条数据的校验错误会一直挂在表单上换数据后依然显示红字用户会以为新数据也有问题。5.3 手动触发校验并拿到首个错误字段validate回调里能拿到所有未通过字段。如果你想滚动到第一个出错的字段并聚焦这样处理this.$refs.formRef.validate((valid, invalidFields) { if (!valid) { const firstKey Object.keys(invalidFields)[0] this.$refs.formRef.scrollToField(firstKey) } })scrollToField是Element Plus 2.1.0才提供的API会自动把第一个错误字段滚动到可视区域。注意版本Element UIVue2版本没有这个方法需要自己手动scrollIntoView。6. 星号背后的三个高频坑踩过的人才懂6.1 坑一rules规则与prop字段名不一致星号显示但校验不触发一个很常见的低级错误el-form-item label用户名 propuserName requiredrules: { username: [{ required: true, message: 请输入用户名, trigger: blur }] }prop写的是userNamerules的key写的是username首字母大小写不一致。这种情况下星号正常显示因为required属性在但提交时validate永远不校验这个字段。排查这类问题建议在rules的key上加一个注释写明对应哪个prop或者统一从props动态生成rules减少手写不一致的可能。6.2 坑二嵌套对象的字段校验表单数据是嵌套对象时prop要带上路径formData: { user: { name: , phone: } }el-form-item label姓名 propuser.name requiredrules的key也要对应写user.namerules: { user.name: [{ required: true, message: 请输入姓名, trigger: blur }] }这种写法容易晕尤其是修改了数据结构后忘记同步prop。我的建议是嵌套层级不要超过两层一旦超过就考虑扁平化数据结构或者单独为子对象建一个子表单组件。否则表单越改越乱星号和校验的对应关系最后谁也说不清。6.3 坑三type为number的输入框值为0被判为空数字输入场景星号显示正确但用户填了0提交时校验还是报错。原因在于Element的required校验内部用value undefined || value null || value 判空0不在空值范围内理论上不会误判。但如果你用了type: number的校验规则且没有绑定v-model.number输入框返回的是字符串0字符串0又是非空字符串也不会报错。真正出现填了0还报错的情况往往是v-model绑定被写成v-model.trim输入框失焦时空格被清掉但值变成了字符串0带引号还是字符串理论不该报错。实测真正容易触发误判的是空字符串和数组长度混在一起时比如daterange选择器取消选择后值为null而规则里写了type: arraynull不是数组直接走type校验失败。解法是在validator里做容错validator: (rule, value, callback) { if (!value || value.length 0) { callback(new Error(请选择时间)) } else { callback() } }7. 我的实操建议哪一种写法最省心踩过这么多坑之后我现在在项目中稳定使用的方案是rules集中管理 el-form-item显式required prop保持严格一致 validator处理动态必填。四件套缺一不可。集中管理的好处是规则和校验逻辑在一处多人协作时不容易出现这个字段到底有没有必填的拉扯。显式required让星号的显示不依赖rules里有没有配——因为有时候rules因为某些原因还没来得及注册required已经能撑住首屏用户体验。prop一致则是老生常谈但确实最多人踩。另外强烈建议在表单组件里封装一个FormItemWrapper自动根据rules生成required状态template el-form-item :labellabel :propprop :required!!required slot / /el-form-item /template封装这个组件的初衷很直接——团队里新人写表单时经常漏掉required属性导致星号不显示。封装后只要在组件上显式声明required就能自动带出也方便统一调整必填样式。8. 最后再分享一个小技巧利用内容变更触发重新校验表单的必填校验触发时机官方大多是blur或change。但有些场景比如用户输入空格、粘贴了一段内容失焦时校验通过了实际值却是空格字符串。Element的required对空格字符串不会判为有效但如果你用trigger: change且输入框没有trim修饰符空格字符串也会被识别为有值。我的做法是对必填的字符串字段统一加v-model.trim并且在rules里自定义一个非空白校验validator: (rule, value, callback) { if (!value || value.trim() ) { callback(new Error(请输入有效内容)) } else { callback() } }这样星号、文案、校验逻辑三者完全对齐用户看到的提示和实际拦截的情况一致。这个细节我调了两次才发现问题根源用户输入了两个空格看起来有内容提交时却提示必填用户很困惑因为界面上的确显示了一串字符。加了trim之后首尾空格直接不进数据体验顺畅很多。Element的必填星号表面上是个小到不能再小的UI细节背后涉及的却是表单校验体系的完整设计。希望这篇内容能帮你理顺星号显示和校验逻辑之间的关系少走我之前走过的弯路。
返回列表