Error in mounted hook: “TypeError: Cannot read property ‘XXXXX‘ of undefined“

it2025-09-07  8

今天使用iview画页面时遇到一个很简单但是搞了很久的bug,加了一个控件

<user-select style="width:200px" @on-change="handleSelect" ref="user" v-model="form.userCode"> </user-select>

然后使用$refs调用组件属性

this.$refs.user.initData();

然后神奇的地方出现了,不管怎么该,一直报Error in mounted hook: "TypeError: Cannot read property 'initData' of undefined"错误,这个方法之前一直用的呀,各种猜想为啥在这里不行了。

最后发现一件神奇的事情,这个组件换个位置就可以正常工作了,然后放回原处就不行了,然后我想,难道这是iview的bug,某两个控件不能紧跟着放在一起?然后又转过头来想,不可能呀,整个vue生态都这么成熟了,不应该会存在这么低级的错误呀!

然后突然发现,这个控件是所在的位置多了一个v-if判断,难道是因为渲染的顺序导致的?

<Row :gutter="32" v-if="type=='2'"> <Col span="12> <FormItem label="用户选择" prop="userCode" > <user-select style="width:200px" @on-change="handleSelect" ref="user" v-model="form.userCode"> </user-select> <FormItem> </Col> <Row>

突然感觉像发现新大陆一样欣喜若狂,果然删掉了v-if属性之后能够正常工作了。

然后想应该是vue的加载渲染机制有关,优先渲染html代码,此时js代码还没有执行,所以动态属性还没有值,因此被v-if包裹的代码块没有被封装,此时执行js初始化代码的时候,调ref组件自然是undefined的。

大胆这么才想后,继续实验猜想,如果真像想的那样,那按照v-if和v-show的区别,v-show会在加载html的时候加载完整代码,只是不展示,那这样的话,执行js代码的时候,组件应该是存在的。所以尝试将v-if改成v-show,果然代码执行成功了。

另一起再回顾一下v-if和v-show的区别:

手段:v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

基于以上区别,因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

最新回复(0)