我们在使用Vue的过程中把注意力都放在了数据操作上,而忽略了关于DOM的一些东西。
场景1:在created生命周期从后端获取数据后想要对DOM进行操作,发生报错,当然这时候DOM元素还没渲染完成怎么会操作成功,但是我就要操作DOM怎么办?
场景2:使用 swiper 插件通过 ajax 请求图片后的滑动问题。
首先我们要对vue的数据更新有一定理解: vue是依靠数据驱动视图更新的,该更新的过程是异步的。即:当侦听到你的数据发生变化时, Vue将开启一个队列(该队列被Vue官方称为异步更新队列)。视图需要等队列中所有数据变化完成之后,再统一进行更新。
例如,当你设置 vm.someData = 'new value'
,该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)
。
1 <div id="App"> 2 <input type="button" value="改变文本" @click="change"> 3 <p ref="myP">{{str}}</p> 4 </div> 5 <script> 6 new Vue({ 7 el:"#App", 8 data:{ 9 str:"我之前很瘦的。" 10 }, 11 methods:{ 12 change(){ 13 this.str = "现在超胖了!"; 14 //此时DOM 并没有更新 15 console.log(this.$refs.myP.innerText)// 输出结果:我之前很瘦的。 16 this.$nextTick(() => { 17 //此时DOM更新了 18 console.log(this.$refs.myP.innerText) // 输出结果:现在超胖了! 19 }) 20 } 21 } 22 }) 23 </script>
因为 $nextTick()
返回一个 Promise
对象,所以你可以使用新的 ES2017 async/await 语法完成相同的事情:
1 methods:{ 2 change(){ 3 this.str = "现在超胖了!"; 4 console.log(this.$refs.myP.innerText)// 我之前很瘦的。 5 await this.$nextTick() 6 console.log(this.$el.textContent) // 现在超胖了! 7 } 8 } 9
nextTick原理
1、异步说明
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新
2、事件循环说明
简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。