Vue2+Vuelidate0x同一表单增改场景下$touch()用法问询
Vue2 + Vuelidate 0.x + Bootstrap-Vue 表单验证实现合理性探讨
我基于Vue2、Vuelidate 0.x和Bootstrap-Vue做表单验证,现有个实现逻辑的疑问想确认是否合理,同时寻求更优方案:
- 创建场景:提交前先判断表单未被触碰(
!this.$v.$dirty)就调用$touch(),再校验是否有效,无效则终止提交 - 编辑场景:表单初始已通过必填项验证,但为了兼容未来新增的验证规则,我写的逻辑是:先判断表单无效且未被触碰(
this.$v.$invalid && !this.$v.$dirty)时调用$touch()并终止提交,之后再校验有效性
当前实现符合预期,但我困惑的是:更新方法里为什么要先判断$invalid再调用$touch()?我原本以为顺序应该反过来。我清楚$touch()的作用是触发错误显示(Vuelidate仅在$invalid且$dirty为true时展示错误提示)。
另外,我不想通过禁用提交按钮或在钩子中提前调用$touch()的方式实现,避免无交互时就显示错误提示。想请教有没有更优的实现方案,或者其他开发者的经验反馈。
相关代码
HTML部分
<b-form> ..... <b-form-group id="title" label="Title" label-for="Title" > <b-form-input id="title-input" v-model="$v.form.title.$model" :state="validateState('title')" type="text" ></b-form-input> <b-form-invalid-feedback id="title-input-live-feedback"> You must enter a title. </b-form-invalid-feedback> </b-form-group> .... </b-form>
JS验证规则
validations: { form: { title: { required } } },
创建方法
async createCompany() { if (!this.$v.$dirty) { this.$v.$touch() } if (this.$v.$invalid) return try { await this.storeCompany() ... } catch (error) { // 错误处理 } },
更新方法
async updateCompany() { if (this.$v.$invalid && !this.$v.$dirty) { this.$v.$touch() return } if (this.$v.$invalid) return try { let response = await CompaniesApi.update(this.id, this.form) ... } catch (error) { // 错误处理 } },
疑问解析与优化建议
关于更新方法的顺序合理性
你当前更新方法的逻辑顺序是合理的,原因如下:
如果先调用$touch()再判断$invalid,会导致不管表单初始是否有效,都强制把所有字段标记为已触碰——哪怕表单原本是有效的,$dirty状态也会被修改,虽然不会显示错误,但属于无意义的状态变更。
而先判断$invalid && !$dirty,是精准命中「初始加载时因新增规则导致表单无效,但用户还未交互」的场景,只在必要时触发$touch()展示错误,完全符合你「无交互不显示错误」的需求。
更优实现方案
1. 抽离通用验证逻辑,减少代码冗余
把创建和更新的验证逻辑合并成通用方法,避免重复代码:
async validateAndSubmit(submitAction) { const isEdit = !!this.id // 根据实际业务调整编辑状态的判断逻辑 // 分场景处理表单触碰逻辑 if (isEdit) { if (this.$v.$invalid && !this.$v.$dirty) { this.$v.$touch() return false } } else { if (!this.$v.$dirty) { this.$v.$touch() } } if (this.$v.$invalid) return false try { await submitAction() // 提交成功后的统一逻辑(如提示、页面跳转) } catch (error) { // 统一错误处理 } return true } // 调用示例 async createCompany() { await this.validateAndSubmit(() => this.storeCompany()) } async updateCompany() { await this.validateAndSubmit(() => CompaniesApi.update(this.id, this.form)) }
2. 优化字段状态计算逻辑
统一validateState方法的逻辑,确保Bootstrap-Vue的状态展示更准确:
validateState(fieldName) { const field = this.$v.form[fieldName] // 未触碰时返回null,不展示状态样式;触碰后根据有效性返回true/false return field.$dirty ? !field.$invalid : null }
3. 增强用户体验:单个字段失焦验证
给输入框添加失焦事件,触发单个字段的$touch(),让用户输入时能及时看到该字段的验证反馈:
<b-form-input id="title-input" v-model="$v.form.title.$model" :state="validateState('title')" type="text" @blur="$v.form.title.$touch()" ></b-form-input>
内容的提问来源于stack exchange,提问作者Snake
相关产品推荐
相关产品推荐

