swiper中包含异步获取数据出现翻页失败问题

309 阅读1分钟

现象描述

点击左右切换,无效,控制台无报错。

原因分析

  • 本来以为是Swiper在响应式数据回来之前已经加载,没有重新初始化swiper,导致该问题。
  • 经调研发现,swiper具有响应式机制,当 data 变化时,Swiper 会自动更新。
  • 真实原因:Swiper的Loop 模式的特殊性:
    1. Loop 模式的复杂性loop: true 时,Swiper 会在真实 slides 前后添加克隆元素来实现无缝循环
    2. 数据变化时的同步问题:当响应式数据变化时,Vue 更新 DOM,但 Swiper 的内部状态(特别是 loop 模式的克隆元素)没有及时更新
    3. 导航按钮失效:如果 Swiper 的内部状态不正确,slidePrev() 和 slideNext() 方法可能无法正常工作。

代码优化

解决方法一: 删除loop模式

<swiper :slides-per-view="1" @swiper="onSwiper">
</swiper>

解决方法二:使用v-if,确保数据有值在初始化swiper

<swiper v-if="list.length > 0" :slides-per-view="1" loop @swiper="onSwiper">
  <!-- 只有当 list 有数据时才渲染 Swiper -->
</swiper>

解决方法三:在数据更新后手动调用 update()

const getList = async () => {
  loading.value = true;
  const res = await getList({
    datas: XXX
  });
  loading.value = false;
  // 等待 DOM 更新完成后,重新初始化 Swiper
  nextTick(() => {
    if (swiperRef.value) {
      swiperRef.value.update(); // 重新计算 slides
      swiperRef.value.slideTo(0, 0); // 跳转到第一张,0ms 动画
    }
  });

  list.value = res.data;
};

解决方法四:使用 key 强制重渲染

<swiper :key="list.length" :slides-per-view="1" loop>
  <!-- 每次数据变化都重新创建实例 -->
</swiper>

各方案优缺点对比

方案优点缺点
删除loop自动响应数据变化失去无缝循环效果
手动更新性能最好,不重新创建实例需要手动维护同步逻辑
条件渲染代码简洁,自动处理同步每次都重新创建实例
key 强制渲染自动处理,更通用每次都重新创建实例