Skip to content

Swiper 自由模式

效果图

流程

注意

  1. 要引入 FreeMode 组件

  2. 设置 freeMode: true

代码

vue
<template>
  <div class="swiperwrap">
    <div class="swipercontent">
      <swiper
        :slidesPerView="3"
        :scrollbar="{ draggable: false }"
        :spaceBetween="30"
        :freeMode="true"
        :modules="modules"
        :loop="true"
        :pagination="paginationref"
        :autoplay="{ delay: 2000, disableOnInteraction: false }"
        @mouseenter="enter"
        @mouseleave="leave"
        @swiper="onSwiper"
        @slideChange="onSlideChange"
      >
        <swiper-slide
          v-for="(item, index) in swiperImgArray"
          :key="index"
          class="swiperItem"
        >
          <img :src="item.img" alt="" />
        </swiper-slide>
      </swiper>
      <!--分页器-->
      <div class="pagination"></div>
    </div>

    <!--左边-->
    <div class="left" @click="handleClick('left')">
      <img
        src="https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2025/MuNiHei20250314/left.png"
      />
    </div>
    <!--右边-->
    <div class="right" @click="handleClick('right')">
      <img
        src="https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2025/MuNiHei20250314/right.png"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { toRaw, ref } from "vue";
import { Swiper, SwiperSlide } from "swiper/vue";
import "swiper/css";
import "swiper/css/pagination";
import {
  Navigation,
  Pagination,
  Scrollbar,
  A11y,
  FreeMode,
  Autoplay,
} from "swiper/modules";
interface Item {
  img: string;
}

const swiperImgArray: Item[] = [
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/01.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/02.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/03.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/04.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/05.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/01.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/02.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/03.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/04.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/05.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/01.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/02.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/03.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/04.jpg",
  },
  {
    img: "https://dianyuan-public.oss-cn-shenzhen.aliyuncs.com/static/2024/muniheipc/munihei/qiangxiankan/05.jpg",
  },
];

let modules = [Navigation, Pagination, Scrollbar, FreeMode, Autoplay];
//定义swiperNew,目的获取非响应式swiper
let swiperNew: any;

//鼠标移入
const enter = () => {
  swiperNew.autoplay.stop();
};
//鼠标移出
const leave = () => {
  swiperNew.autoplay.start();
};
const onSwiper = (swiper: any) => {
  swiperNew = toRaw(swiper); //拿到swiper对象再转换为非响应式
};
const onSlideChange = () => {
  console.log("slide change");
  console.log(swiperNew);
};

const paginationref = ref({
  el: ".pagination",
  clickable: true,
  bulletClass: "pagination-item",
  bulletActiveClass: "active",
  renderBullet: (index: number, className: string) => {
    return `<div class="${className}"><div class="pagination-item-inner">${
      index + 1
    }</div></div>`;
  },
});

const handleClick = (direction: string) => {
  if (direction === "left") {
    swiperNew.slidePrev();
  } else {
    swiperNew.slideNext();
  }
};
</script>

<style lang="scss" scoped>
.swiperwrap {
  width: 900px;
  height: 373px;
  background: red;
  margin: 0 auto;
  position: relative;
  margin-top: 120px;
  .swipercontent {
    width: 508px;
    height: 95px;
    position: absolute;
    left: 50%;
    top: 45%;
    transform: translate(-50%, -50%);
    img {
      width: 100%;
      height: 100%;
    }

    .swiperItem {
      // border: aqua solid 1px;
      // height: 200px;
    }
  }
  .left {
    width: 33px;
    height: 59px;
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    cursor: pointer;
  }
  .right {
    width: 33px;
    height: 59px;
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    cursor: pointer;
  }
  :deep(.swiper-pagination)
    .swiper-pagination-bullet.swiper-pagination-bullet-active {
    background-color: green;
  }

  :deep(.swiper-pagination-bullet) {
    //修改分页器圆点大小
    width: 30px;
    height: 30px;
    background-color: #fff;
  }

  .swiper-horizontal > .swiper-pagination-bullets .swiper-pagination-bullet,
  :deep(.swiper-pagination-horizontal.swiper-pagination-bullets)
    .swiper-pagination-bullet {
    // 分页器远点之间的距离
    margin: 0 10px;
  }
  .pagination {
    width: 210px;
    height: 38px;
    position: absolute;
    left: 50%;
    bottom: -57px;
    transform: translateX(-50%);
    ::v-deep(.pagination-item) {
      width: 30px;
      height: 30px;
      border-radius: 50%;
      background: white;
      margin-top: 5px;
      margin-left: 10px;
      cursor: pointer;
      float: left;
      &.active {
        background: GREEN;
        .pagination-item-inner {
          color: yellow;
        }
      }
      .pagination-item-inner {
        width: 100%;
        height: 100%;
        line-height: 20px;
        display: flex;
        justify-content: center;
        align-items: center;
        color: black;
        text-align: center;
      }
    }
  }
}
</style>