0 问题出现
接手了旧代码,需要将控制表单条件展示的变量(下文称为control)从同步计算值改为接口获取的值。
修改逻辑之后,校验出现问题。
1 问题复现情景
v-if推迟加载整张表单,加载表单后,watch中触发校验。Mounted时,通过修改control控制替换部分的el-form-item。
实际的业务场景是,原来control是同步值,在data内同步获取。后续control变为异步值,从接口获取。
2 问题现象
错误的校验信息出现在了页面。
3 问题产生原因
实际上问题目前观测到有两种表现情况,具体视代码实现情况。
情况1:后续校验均失效,无法正常校验。
根据断点排查,可以看到el-input在内部dispatch事件之后,外层的el-form-item没有接收到事件。
情况2:留存了错误校验,再次触发可以消去。
watch的触发先于mounted,提前对错误的值进行校验。后续vdom虽然变化,但vue复用了DOM,导致显示出错。
4 问题根本原因
a watch中使用$refs进行校验造成错误。
b vue的diff算法DOM复用。
5 问题解决办法
对于情况1,control变量不要有初始值。也不要能够再次变化。
对于情况1、2,都不要在watch中调用$refs进行校验,因为这个校验在赋值表单之前就被触发了。
可以通过对每个el-form-item加key属性来确保真实DOM不被错误复用,换句话说,能够用v-for生成表单就不要手写。
参考:Vue-处理边界情况