vue3中使用swiper实现平滑走马灯

5,409 阅读3分钟

在标准配置下,Swiper组件呈现出的基本轮播效果是逐个轮播,而非连续平滑滚动的走马灯效果。 2.gif 若要实现平滑滚动,且可手动切换,需要对Swiper进行一些定制化调整,包括但不限于:

  1. 选择合适的插件
  2. 监听切换事件
  3. 修改动画效果

屏幕录制2024-06-20 10.23.38.gif

Swiper基础使用

swiper提供了vue的版本,官网在这:swiperjs.com/vue

Swiper Vue.js 插件作为 Swiper 主库的一部分,仅通过 NPM 提供:

npm i swiper

通过 swiper/vue 中引入两个组件 SwiperSwiperSlide

<script setup>
import { Swiper, SwiperSlide } from 'swiper/vue'
import 'swiper/css'
</script><template>
  <Swiper>
    <SwiperSlide v-for="item in 8" :key="item" class="bg-blueGray">
      <div class="h-300px">
        Slide {{ item }}
      </div>
    </SwiperSlide>
  </Swiper>
</template>
  

这样就实现了一个最基础的手动切换轮播图

屏幕录制2024-06-20 13.26.40.gif

参数

可以设置一些参数来满足定制化的需求,如:

  • slidesPerView:默认可见的slide数量,可以指定某个具体的数字或者'auto'
  • spaceBetween:slide的边距,单位是px。
  • speed:slide之间的过渡时间(毫秒)

可在官网查看所有支持的参数,某些参数需要引入对应的modules,如autoplay,free-mode

​
  <Swiper
    :slides-per-view="4"
    :space-between="20"
    :speed="2000"
  >
  ...
  </Swiper>

加了以上参数以后,swiper的效果,划动切换以后的时间将持续2秒

image.png

方法

自动滚动

swiper/vue 的自动滚动,直接加 autoplay 是没用的,需要从 swiper/modules 引入 Autoplay官网指路

<script setup>
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Autoplay } from 'swiper/modules'
import 'swiper/css'</script><template>
  <Swiper
    :slides-per-view="4"
    :space-between="20"
    :speed="2000"
    :modules="modules"
    autoplay
    loop
  >
    <SwiperSlide v-for="item in 8" :key="item" class="bg-black">
      <div class="h-300px c-white">
        Slide {{ item }}
      </div>
    </SwiperSlide>
  </Swiper>
</template>

autoplay 也是可以作为一个对象,单独设置一些属性的,如:

获取swiper实例

正常情况下,在vue中,是通过给dom节点设置ref属性,来获取dom实例,但是swiper的方法并不在通过ref获取的实例中,要获取swiper真正的实例,需要监听swiper方法获取,可以输出对比一下

<script setup>
import { Swiper, SwiperSlide } from 'swiper/vue'
import 'swiper/css'const swiperInstance = ref(null)
function onSwiper(swiper) {
  console.log(swiper, swiperInstance.value)
}
</script><template>
  <Swiper
    ref="swiperInstance"
    @swiper="onSwiper"
    ...
  >
    ...
  </Swiper>
</template>

image.png

image.png

自定义切换

获取了swiper实例以后,就能通过它调用swiper对应的方法了,如这里需要定制的手动切换,全部的方法可在官网查看。

切换的方法,如果对定制要求不是很高,可以直接引入 pagination 的moudule。

这里实现的是自定义了两个切换按钮,当切换时,需要停止当前的自动播放动画,然后做一些边界值的变化,这里不直接使用swiper.slideNextswiper.slidePrev的原因是,这样切换的时候swiper还是要等当前silde结束自动切换以后,再切换到下一张,不是立马切换的效果,所以这里使用 swiper.slideToLoop 达到一个立即切换的效果。

<script setup>
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Autoplay } from 'swiper/modules'import 'swiper/css'const modules = [Autoplay]
const swiperInstance = ref(null)
​
function onSwiper(swiper) {
  swiperInstance.value = swiper
}
​
let autoplayTimer = null
function handleNext(type) {
  const swiper = swiperInstance.value
  swiper.autoplay.stop()
  if (type === 'prev') {
    swiper.slideToLoop(swiper.realIndex <= 1 ? 7 : swiper.realIndex - 1, 500)
  }
  else {
    swiper.slideToLoop(swiper.realIndex >= 7 ? 0 : swiper.realIndex + 1, 500)
  }
  clearInterval(autoplayTimer)
  autoplayTimer = setTimeout(() => {
    swiper.autoplay.start()
  }, 2000)
}
</script><template>
  <div>
    <Swiper
      :slides-per-view="4"
      :space-between="20"
      :speed="1000"
      :modules="modules"
      loop
      :autoplay="{ delay: 500 }"
      @swiper="onSwiper"
    >
      <SwiperSlide v-for="item in 8" :key="item" class="bg-blueGray">
        <div class="h-300px">
          Slide {{ item }}
        </div>
      </SwiperSlide>
    </Swiper>
    <el-button @click="handleNext('prev')">
      <div class="i-ms-chevron-left" />
    </el-button>
    <el-button @click="handleNext('next')">
      <div class="i-ms-chevron-right" />
    </el-button>
  </div>
</template>

屏幕录制2024-06-21 09.35.22.gif

平滑滚动

最后要达到平滑滚动的效果,需要引入一个 free-mode 的module,因为是平滑,所以 autoplay.delay 就需要设置为0了,最后一步就是修改swiper的动画效果,以下是完整代码,效果就是文章开头的效果

<script setup>
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Autoplay, FreeMode } from 'swiper/modules'import 'swiper/css'
import 'swiper/css/free-mode'const modules = [Autoplay, FreeMode]
const swiperInstance = ref(null)
​
function onSwiper(swiper) {
  swiperInstance.value = swiper
}
​
let autoplayTimer = null
function handleNext(type) {
  const swiper = swiperInstance.value
  swiper.autoplay.stop()
  if (type === 'prev') {
    swiper.slideToLoop(swiper.realIndex <= 1 ? 7 : swiper.realIndex - 1, 500)
  }
  else {
    swiper.slideToLoop(swiper.realIndex >= 7 ? 0 : swiper.realIndex + 1, 500)
  }
  clearInterval(autoplayTimer)
  autoplayTimer = setTimeout(() => {
    swiper.autoplay.start()
  }, 2000)
}
</script><template>
  <div>
    <Swiper
      :slides-per-view="4"
      :space-between="20"
      :speed="1000"
      :modules="modules"
      :autoplay="{ delay: 0 }"
      loop
      @swiper="onSwiper"
    >
      <SwiperSlide v-for="item in 8" :key="item" class="bg-blueGray">
        <div class="h-300px">
          Slide {{ item }}
        </div>
      </SwiperSlide>
    </Swiper>
    <el-button @click="handleNext('prev')">
      <div class="i-ms-chevron-left" />
    </el-button>
    <el-button @click="handleNext('next')">
      <div class="i-ms-chevron-right" />
    </el-button>
  </div>
</template><style>
.swiper-free-mode .swiper-wrapper {
  transition-timing-function: linear;
}
</style>