Swiper和Vue配合使用的问题——Vue的异步更新DOM
Swiper是很常用的库,用于实现触摸滑动效果,为了让Swiper生效,需要执行类似下面的代码(摘自Swiper官方示例)
var mySwiper = new Swiper(‘.swiper-container‘, { autoplay: true,//可选选项,自动滑动 })
而该代码的执行时机必须在DOM渲染完成之后,因此Swiper的官方文档要求在window.onload或$(document).ready()(使用JQuery或Zepto时)调用。
但显然,这只适用于静态页面。
如果Swiper中的数据是动态渲染的,且可能会通过Ajax请求获得最新的值而不断变化,那我们在什么时机去调用呢?
是不是数据被修改了就可以调用呢?因为Vue.js的双向绑定特性,数据被修改页面就会被重新渲染。
答案是否定的。
可能你还没有注意到,Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.then
、MutationObserver
和 setImmediate
,如果执行环境不支持,则会采用 setTimeout(fn, 0)
代替。
例如,当你设置 vm.someData = ‘new value‘
,该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)
。这样回调函数将在 DOM 更新完成后被调用。
——摘自Vue.js官方文档
<br />
因此我们就可以把Swiper的初始化放在<code>Vue.nextTick(callback)接收的回调函数中去。
如果你的Ajax请求直接在当前Vue示例的方法中调用(没有使用Vuex),那么可以在Ajax请求成功的回调中注册nextTick事件。
axios.get("/api/xxx").then(res=>{ this.$nextTick(()=>{ var mySwiper = new Swiper(‘.swiper-container‘, { autoplay: true,//可选选项,自动滑动 }) }) //this指当前Vue实例 })
这样就能确保调用时页面的DOM已经被更新。
如果使用了Vuex,那么Ajax的操作一般会放在Vuex中的action里,因此我们在当前页面中就不能使用上面那种方法了。
需要给对应的数据加上一个watcher,这样action通过mutation更改数据时,我们的watcher监视器也会被调用,
我们可以在watcher里面去注册this.$nextTick事件,方法同上。