问题描述:
项目里有一个轮播图,轮播图的图片数据从服务器获取,用v-for生成DOM在页面中显示,轮播图插件会通过new Swiper给DOM添加CSS、事件等,实现轮播效果。
在这里存在操作顺序问题:当服务器返回图片数据后,需要更新数据。数据更新后,v-for根据数据先加载完毕,轮播图插件swiper再通过new Swiper操作DOM,否则轮播效果不会起效。
v-for生成DOM:
<div class="center"><div class="swiper-container" ref="mySwiper"><div class="swiper-wrapper"><div class="swiper-slide" v-for="imagesData in imagesList" :key="imagesData.id"><img :src="imagesData.imgUrl"></div></div><div class="swiper-pagination"></div><div class="swiper-button-prev"></div><div class="swiper-button-next"></div></div></div>
异步请求数据:
this.$store.dispatch('Home/getBannerList');//store语句const mutations = {setBannerList(state, data){state.bannerList = data;}
};const actions = {async getBannerList(context){let bannerData = await requestBannerImage();bannerData = bannerData.data;context.commit('setBannerList',bannerData);}
};
Swiper操作DOM:
let mySwiper = new Swiper('.swiper-container', {//开启循环模式loop: true,// 如果需要分页器pagination: {el: '.swiper-pagination',},// 如果需要前进后退按钮navigation: {nextEl: '.swiper-button-next',prevEl: '.swiper-button-prev',},});
把逻辑处理放在mounted钩子中,存在的问题:由于请求是异步获取,在mounted中虽然其他DOM已经加载,但是数据还未完全返回,因此v-for还未执行完毕,相当于v-for的加载也是异步的。new Swiper时,v-for的DOM还未生成,因此对DOM操作无法生效。
解决方案:
使用nextTick()
简单介绍nextTick(回调函数):等待下一次 DOM 更新刷新的工具方法。
当页面中DOM发生变化时,并不会马上更新页面,而是把修改推入队列,再统一处理。
nextTick()执行后,可以让推入队列中的DOM修改生效。nextTick中的回调会在修改生效后执行。
用watch()监听列表数据的改变,列表数据改变后,用nextTick推到DOM上,再用Swiper操作DOM。
watch:{List:{handler(newValue, oldValue){this.$nextTick(()=>{... = new Swiper()})}}
}