(一)iview的校验TypeError: Cannot read property 'validateField' of undefined"
一、问题描述
我是在自己封装了一个地址级联选择,然后想要每次改变了其中数据的时候,就进行一次单独校验,所以用到了iview对部分表单字段进行校验的方法validateField。其实一开始使用的时候是没有任何问题的,问题出现的原因是我有多个表单,每次只显示一个表单,可以来回切换,如下图。我使用的是v-if来控制表单2和表单3的显示与隐藏,在我填完信息2以后进入到信息3,然后再点击回去信息2的时候,便报错了:TypeError: Cannot read property 'validateField' of undefined"
二、问题关键
我就很奇怪为什么我一开始的校验是好的,返回来此表单就会出错呢,这对单个表单校验出错也太坑了吧。然后我打印了this.$refs.['formTwo']发现打印的是undefined,也就是说根本就不是表单校验出了问题,而是在于压根就找不到这个DOM对象。
关键点在于,Vue 在更新 DOM 时是异步执行的,而我我使用了v-if来控制所有表单内容的显隐,而v-if它通过动态的摧毁DOM又构建,来控制元素的显隐。在我重新切回表单2的时候,原来的DOM早已被摧毁,此时又还未创建完成。
三、解决办法
1、我想到的第一个办法是使用v-show;v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过控制DOM元素的display样式来到达显隐,之前在写富文本编辑切换的时候也出现什么东西undefined,错误同样的原因也是我使用了v-if来控制每一个富文本编辑,后来改为v-show之后,解决了问题。
而在这个地方,这样改随之而来的另一个问题是我所有的表单在一开始的时候都出现了,我知道这肯定是和我的判断条件写的不对有关,可我又不想改,于是有了第二个解决方法。
2、使用nextTick。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)
。这样回调函数将在 DOM 更新完成后被调用。于是我将该句单独校验表单的代码写在了里面,问题解决~ 如下:
this.$nextTick(() => { this.$refs.['formTwo'].validateField('street') });
四、相关知识点
v-if和v-show的区别(使用v-if的时候一定要好好考虑清楚!)
vue异步加载dom(参考:https://cn.vuejs.org/v2/guide/reactivity.html)
如何单独校验某一表单项