问题描述:
在mounted中打印this.$refs
时可以获取到数据
但打印this.$refs.text1
时,则获取不到数据,显示undefined
。
后续:通过使用this.$nextTick
后有些场景可获取到数据,但有些场景依旧获取不到数据,还是显示undefined
。
原因分析:
mounted 阶段是加载阶段,有些DOM可能存在还没有完成的情况。
搜索到的解释:
当使用$nextTick
时,将在微任务(不支持微任务的浏览器将回退至宏任务)堆栈中入栈写的回调。如果所有子组件都已经下载完毕,并在Vue中定义,则从根组件往后渲染时,因为用的都是同步方法,微任务将在这些同步方法后被执行,所以大多数时候可以通过$nextTick
获取子组件渲染后的DOM节点。但是如果实例化组件的时候,有其他微任务入栈,就要看微任务队列的执行顺序了,所以无法完全保证。对于异步组件,由于网络原因,import微任务总在$nextTick
之后,所以总是拿不到子组件的DOM。
个人的一些理解:
1、当要获取的数据是异步获取时,mounted执行的时候,数据还未被获取到,$nextTick
的触发在数据异步获取之前?
2、使用了v-if
,v-for
,v-show
这些指令时,会根据不同的条件去动态的渲染DOM树,此时DOM在mounted阶段是不存在的;
解决方案:
通过查询资料,因为ref本身是作为渲染结果被创建的,在渲染的时候是不能访问的,因为他们还不存在。$refs
不是响应式的,只在组件渲染完成后才填充”,所以可以在DOM渲染完毕后再进行获取。和this.$nextTick
结合使用,nextTick 是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用$nextTick,则可以在回调中获取更新后的 DOM。
在this.$nextTick
外面再用一个setTimeout,由于setTimeout
是宏任务,所以一般会在渲染后执行。但对于异步组件,如果由于网络延迟,导致微任务在宏任务之后入栈,则在setTimeout
的回调中仍无法获取子组件的DOM。简单的来说,由于有异步执行顺序的影响,只能保证单独组件内部的执行顺序,无法保证其他组件的解析注册执行顺序。
总结:
当遇到该问题时,可先添加this.$nextTick
来解决,如果无法解决,可在this.$nextTick
使用setTimeout
、promise
等异步来解决。