vue 之 $nextTick
官方说明:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
疑问:
- DOM 更新循环是指什么?
- 下次更新循环是什么时候?
- 修改数据之后使用,是加快了数据更新进度吗?
- 在什么情况下要用到?
原理
vue的响应式并不是数据发生变化之后DOM立即变化,而是按照一定的方式进行DOM的更新
第一个案例:
<template>
<div id="app">
<input type="text" ref="ipt" v-if="isShow" />
<button @click="fn" v-else>点击修改</button>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
isShow: false,
};
},
methods: {
fn() {
this.isShow = true;
console.log(this.$refs.ipt); // undefined
this.$refs.ipt.focus() //报错
},
},
};
</script>
<style></style>
遇到上述情况怎么解决呢?
this.isShow = true; setTimeout(() => { console.log(this.$refs.ipt); //<input type="text">
this.$refs.ipt.focus()
}, 0);
//或者
this.$nextTick(() => {
console.log(this.$refs.ipt); //<input type="text">
this.$refs.ipt.focus()
});
分析:因为 this.isShow = true;时,虚拟dom需要通过diff算法进行更新,这个过程是需要时间的,而同步的代码中,this.$refs.ipt 所需时间 小于 这个渲染时间
第二个案例
<template> <section> <h1 ref="hello">{{ value }}</h1> <el-button type="danger" @click="get">点击</el-button> </section> </template> <script> export default { data() { return { value: 'Hello World ~' }; }, methods: { get() { this.value = '你好啊'; console.log(this.$refs['hello'].innerText); // Hello World ~ this.$nextTick(() => { console.log(this.$refs['hello'].innerText); // 你好啊 }); } }, mounted() { }, created() { } } </script>
应用场景:
需要在视图更新之后,基于新的视图进行操作
思考的问题:$nextTick 如何 结合 created 和 mounted 来处理问题
疑问:
疑问一 . this.$nextTick 为什么要放在 created 或者 mounted ,有什么区别
疑问二 . 为什么$nextTick能保证子组件都加载完?
第一步:了解 created
//组件创建之后 created() { // 可以操作数据,发送ajax请求,并且可以实现 // vue对页面的影响 应用:发送ajax请求 console.log('组件创建后:'+this.msg); //哈哈哈 }
第二步:了解mounted
//装载数据到DOM之后 mounted() { // 可以操作DOM console.log('DOM装载后:'+document.getElementById('app')); //<div id="app"><div id="test"></div></div> }
第三步:分析
疑问一
1.例如在parent 里面有 两个child组件,但是父组件通过异步获取的数据data(created),data里面有childData1 和 childData2 那么此时通过this.$refs.child1是获取不到的,所以需要用到 this.$nextTick,这样可以解决刚才的案例问题(但是,若是同步的组件,那么在parent里面的 mounted 获取 this.$refs.child1也是可以的,那么就不需要该死的this.$nextTick)
2.将this.$nextTict 写在 created 和 mounted 没太大的区别,只是created 会优先 mounted执行,参考 vue 之 生命周期(钩子)
疑问二
如果是同步子组件,mounted
就已经能保证了同步子组件都加载完了。因为对于一个页面来说,第一次 DOM 更新循环结束,也就是 mounted
的时候。
同步顺序是 parent created
→ child created
→ child mounted
→ child $nextTick
→ parent mounted
→ parent $nextTick
。
如果是异步子组件,你需要在 mounted
里写 $nextTick
,但也并不能完全保证子组件加载完毕,因为异步子组件里还可以再套异步孙子组件。
总而言之,同步子组件,写 created
+ $nextTick
和写 mounted
都行;异步子组件,除非是在父组件中直接操作异步子组件的生命周期钩子、或者子组件通过 $emit
的方式通知父组件,否则单纯靠父组件自己,是无法百分百保证的。
参考:http://errornoerror.com/question/10048646268771205890/