Vue3使用触摸滑动插件(Swiper)

68 篇文章 4 订阅
66 篇文章 3 订阅

Vue2使用触摸滑动插件(Swiper)

参考文档:

本文使用版本:Swiper@11.1.4

安装插件:pnpm i swiper

本文基于Swiper插件进行封装,主要实现两种形式的轮播图展示:

  • 首页轮播图切换展示(type: banner)

  • 走马灯轮播图滚动展示(type: carousel)

  • 信息展播模式(type: broadcast)

可自定义设置以下属性:

  • 轮播图片数组(images),类型:Array<{title: string, link?: string, src: string}>,默认 []

  • 图片宽度(width),类型:number | string,默认 '100%'

  • 图片高度(height),类型:number | string,默认 '100vh'

  • banner轮播图模式 | carousel走马灯模式(type),类型:'banner'|'carouse'|'broadcast',默认 'banner'

  • 是否显示导航(navigation),类型:boolean,默认 true

  • 自动切换的时间间隔(type: banner时生效)(delay),单位ms,类型:number,默认 3000

  • 是否可以鼠标拖动(swipe),类型:boolean,默认 true

  • 预加载时的loading颜色(preloaderColor),类型:'theme'|'white'|'black',默认 'theme',可选 theme(主题色) | white | black

效果如下图:在线预览

首页轮播图 type: banner

走马灯 type: carousel 

信息展播 type: broadcast

①创建触摸滑动组件Swiper.vue:

<script setup lang="ts">
import type { Swiper as SwiperTypes } from 'swiper/types'
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Pagination, Navigation, Autoplay, EffectFade, Mousewheel } from 'swiper/modules'
import 'swiper/css'
import 'swiper/css/navigation'
import 'swiper/css/pagination'
import 'swiper/css/effect-fade'
import { ref, computed } from 'vue'
interface Image {
  title: string // 图片名称
  link?: string // 图片跳转链接
  src: string // 图片地址
}
interface Props {
  images: Image[] // 轮播图片数组
  width?: number|string // 图片宽度
  height?: number|string // 图片高度
  type?: 'banner'|'carousel'|'broadcast' // banner轮播图模式 | carousel走马灯模式
  navigation?: boolean // 是否显示导航
  delay?: number // 自动切换的时间间隔(type: banner时生效),单位ms
  // speed?: number // 切换动画持续时间,单位ms
  swipe?: boolean // 是否可以鼠标拖动
  preloaderColor?: 'theme'|'white'|'black' // 预加载时的loading颜色
}
const props = withDefaults(defineProps<Props>(), {
  images: () => [],
  width: '100%',
  height: '100vh',
  type: 'banner', // 可选 banner | carousel
  navigation: true,
  delay: 3000,
  // speed: 300,
  swipe: true,
  preloaderColor: 'theme' // 可选 theme white black
})
const imgWidth = computed(() => {
  if (typeof props.width === 'number') {
    return props.width + 'px'
  } else {
    return props.width
  }
})
const imgHeight = computed(() => {
  if (typeof props.height === 'number') {
    return props.height + 'px'
  } else {
    return props.height
  }
})
const modulesBanner = ref([Navigation, Pagination, Autoplay, EffectFade])
const autoplayBanner = ref({
  delay: props.delay,
  disableOnInteraction: false, // 用户操作swiper之后,是否禁止autoplay。默认为true:停止。
  pauseOnMouseEnter: true // 鼠标置于swiper时暂停自动切换,鼠标离开时恢复自动切换,默认false
})

const modulesCarousel = ref([Autoplay])
const autoplayCarousel = ref<object|boolean>({
  delay: 0,
  disableOnInteraction: false
})
const modulesBroadcast = ref([Navigation, Pagination, Mousewheel])
const emits = defineEmits(['swiper', 'change'])
function onSwiper (swiper: SwiperTypes) {
  // console.log(swiper)
  emits('swiper', swiper)
  if (props.type === 'carousel') {
    swiper.el.onmouseenter = () => { // 移入暂停
      swiper.autoplay.stop()
    }
    swiper.el.onmouseleave = () => { // 移出启动
      swiper.autoplay.start()
    }
  }
}
</script>
<template>
  <swiper
    v-if="type==='banner'"
    :class="{'swiper-no-swiping': !swipe}"
    :modules="modulesBanner"
    :navigation="navigation"
    :slides-per-view="1"
    :autoplay="autoplayBanner"
    lazy
    loop
    @swiper="onSwiper"
    @slideChange="(swiper) => $emit('change', swiper)"
    v-bind="$attrs">
    <swiper-slide v-for="(image, index) in images" :key="index">
      <a :href="image.link ? image.link:'javascript:;'" :target="image.link ? '_blank':'_self'" class="m-link">
        <img
          :src="image.src"
          class="u-img"
          :style="`width: ${imgWidth}; height: ${imgHeight};`"
          :alt="image.title"
          loading="lazy" />
      </a>
      <div :class="`swiper-lazy-preloader swiper-lazy-preloader-${preloaderColor}`"></div>
    </swiper-slide>
  </swiper>
  <swiper
    v-if="type==='carousel'"
    class="swiper-no-swiping"
    :modules="modulesCarousel"
    :autoplay="autoplayCarousel"
    lazy
    loop
    @swiper="onSwiper"
    @slideChange="(swiper) => $emit('change', swiper)"
    v-bind="$attrs">
    <swiper-slide v-for="(image, index) in images" :key="index">
      <a :href="image.link ? image.link:'javascript:;'" :target="image.link ? '_blank':'_self'" class="m-link">
        <img
          :src="image.src"
          class="u-img"
          :style="`width: ${imgWidth}; height: ${imgHeight};`"
          :alt="image.title"
          loading="lazy" />
      </a>
      <div :class="`swiper-lazy-preloader swiper-lazy-preloader-${preloaderColor}`"></div>
    </swiper-slide>
  </swiper>
  <swiper
    v-if="type==='broadcast'"
    :modules="modulesBroadcast"
    :navigation="navigation"
    lazy
    @swiper="onSwiper"
    @slideChange="(swiper) => $emit('change', swiper)"
    v-bind="$attrs">
    <swiper-slide v-for="(image, index) in images" :key="index">
      <a :href="image.link ? image.link:'javascript:;'" :target="image.link ? '_blank':'_self'" class="m-link">
        <img
          :src="image.src"
          class="u-img"
          :style="`width: ${imgWidth}; height: ${imgHeight};`"
          :alt="image.title"
          loading="lazy" />
      </a>
      <div :class="`swiper-lazy-preloader swiper-lazy-preloader-${preloaderColor}`"></div>
    </swiper-slide>
  </swiper>
</template>
<style lang="less" scoped>
.m-link {
  display: block;
  height: 100%;
}
.u-img {
  object-fit: cover;
  cursor: pointer;
}
.swiper {
  --swiper-theme-color: @themeColor;
}
:deep(.swiper-wrapper) { // 自动切换过渡效果设置
  transition-timing-function: linear; // 线性过渡模拟走马灯效果
  -webkit-transition-timing-function: linear;
}
:deep(.swiper-pagination-bullet) {
  width: 12px;
  height: 12px;
}
.swiper-lazy-preloader-theme {
  --swiper-preloader-color: @themeColor;
}
</style>

②在要使用的页面引入:

<script setup lang="ts">
import Swiper from './Swiper.vue'
import pkg from '/package.json'
import { ref, shallowReactive, onBeforeMount } from 'vue'

const images = ref<any[]>([])
function loadImages () {
  for (let i = 1; i <= 10; i++) {
    images.value.push({
      title: `image-${i}`,
      link: `https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/${i}.jpg`,
      src: `https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/${i}.jpg`
    })
  }
}
onBeforeMount(() => { // 组件已完成响应式状态设置,但未创建DOM节点
  loadImages()
})
function onChange (swiper: any) {
  console.log('slider change', swiper)
}
const navigation = shallowReactive<{[key: string]: any}>({})
function onSwiper (swiper: any) {
  navigation.prevEl = swiper.navigation.prevEl
  navigation.prevEl.style.display = 'none'
  navigation.nextEl = swiper.navigation.nextEl
  navigation.nextEl.style.display = 'none'
}
function onPrev () {
  navigation.prevEl.click()
}
function onNext () {
  navigation.nextEl.click()
}
</script>
<template>
  <div>
    <h1>Swiper 参考文档</h1>
    <ul class="m-list">
      <li>
        <a class="u-file" href="https://swiperjs.com/" target="_blank">Swiper官方</a>
      </li>
      <li>
        <a class="u-file" href="https://swiperjs.com/swiper-api" target="_blank">Swiper API</a>
      </li>
      <li>
        <a class="u-file" href="https://swiperjs.com/vue" target="_blank">Swiper Vue</a>
      </li>
      <li>
        <a class="u-file" href="https://swiperjs.com/demos" target="_blank">Swiper Demos</a>
      </li>
    </ul>
    <Space align="top" class="mt30" :size="6">
      <h1>Swiper</h1>
      <Tag color="volcano">{{ pkg.dependencies.swiper }}</Tag>
    </Space>
    <h2 class="mt30 mb10">基本使用</h2>
    <Swiper
      :images="images"
      :height="600"
      :pagination="{
        dynamicBullets: true,
        clickable: true
      }"
      @change="onChange" />
    <h2 class="mt30 mb10">走马灯</h2>
    <Swiper
      :images="images"
      type="carousel"
      :height="240"
      :slides-per-view="3"
      :space-between="20"
      :speed="2500" />
    <h2 class="mt30 mb10">信息展播</h2>
    <Space>
      <Button @click="onPrev">Prev</Button>
      <Button @click="onNext">Next</Button>
    </Space>
    <br/>
    <br/>
    <Swiper
      :images="images"
      type="broadcast"
      :pagination="{
        dynamicBullets: true,
        clickable: true
      }"
      :height="320"
      :slides-per-view="3"
      :space-between="30"
      loop
      mousewheel
      @swiper="onSwiper" />
  </div>
</template>
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值