直接上代碼:
<template>
<div
id="hy-swiper"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<div class="swiper">
<div v-for="item in banners" class="swiper-item">
<a :href="item.link"><img :src="item.image" alt="" /></a>
</div>
</div>
<div class="swiper-circle">
<ul>
<li
v-for="(item, index) in swiperItemCount"
:class="currentIndex == item ? 'swiperItemActive' : ''"
@click="clickItem(item)"
></li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: "Swiper",
props: {
banners: {
// 圖片內容
type: Array,
default() {
return [];
},
},
},
data() {
return {
swiperItemCount: 0, // 輪播圖數
swiperStyle: "", // swiper的樣式
currentIndex: 1, // 當前的 index
moveRatio: 0.25, // 跳轉下一張圖片所需的移動距離比例
};
},
methods: {
// 設置滾動位置
setTransform(position) {
this.swiperStyle.transform = `translate3d(${position}px, 0, 0)`;
this.swiperStyle[
"-webkit-transform"
] = `translate3d(${position}px), 0, 0`;
this.swiperStyle["-ms-transform"] = `translate3d(${position}px), 0, 0`;
},
// 設置滾動過渡動畫
setTransition() {
this.swiperStyle.transition = `transform 300ms`;
},
// 1.先操作 dom 元素
handleDom() {
// 獲取 dom 對象
let swiper = document.querySelector(".swiper");
this.swiperItemCount = swiper.children.length;
// 復制第一張圖片和最后一張圖片,分別放在最后面和最前面
let nodeFirst = swiper.children[0].cloneNode(true);
let nodeLast = swiper.children[this.swiperItemCount - 1].cloneNode(true);
swiper.appendChild(nodeFirst); // 如果 cloneNode 報錯,那么只能在 dom 中直接添加最后一個圖片了
swiper.insertBefore(nodeLast, swiper.children[0]);
this.swiperStyle = swiper.style;
this.totalWidth = swiper.offsetWidth;
// 此時,currentIndex 的初始值為 1 ,那么先顯示第二張圖片
this.setTransform(-this.currentIndex * this.totalWidth);
},
// 2. 實現用戶觸摸移動,圖片也跟隨移動,並根據滑動的方向跳轉下一張圖片的功能
//觸摸開始
touchStart: function (e) {
// 停止定時器
this.stopTimer();
// 獲取並保存開始觸摸的位置
this.startX = e.touches[0].pageX;
},
// 觸摸過程
touchMove(e) {
// 計算出用戶拖動的距離
this.currentX = e.touches[0].pageX;
this.distance = this.currentX - this.startX;
let currentPosition = -this.currentIndex * this.totalWidth;
let moveDistance = this.distance + currentPosition;
// 設置當前的位置,也就是隨着觸摸移動,圖片也跟隨移動
this.setTransform(moveDistance);
},
// 觸摸結束,根據滑動的方向跳轉下一張圖片
touchEnd: function (e) {
let distance_abs = Math.abs(this.distance);
if (this.distance == 0) {
return;
} else if (
this.distance < 0 &&
distance_abs >= this.moveRatio * this.totalWidth
) {
this.currentIndex++;
} else if (
this.distance > 0 &&
distance_abs >= this.moveRatio * this.totalWidth
) {
this.currentIndex--;
}
this.setTransition();
this.setTransform(-this.currentIndex * this.totalWidth);
this.currentScroll();
this.swiperAuto();
},
// 3.判讀第一張和最后一張圖片的邏輯滾動,設置正確的滾動,抽取為函數
currentScroll() {
if (this.currentIndex == this.swiperItemCount + 1) {
this.currentIndex = 1;
} else if (this.currentIndex == 0) {
this.currentIndex = this.swiperItemCount;
}
setTimeout(() => {
this.swiperStyle.transition = "0ms";
this.setTransform(-this.currentIndex * this.totalWidth);
}, 300);
},
// 4. 實現點擊小圓圈跳轉相應的圖片
clickItem(item) {
this.stopTimer();
this.currentIndex = item;
this.setTransform(-this.currentIndex * this.totalWidth);
this.swiperAuto();
},
// 5.設置定時器,實現輪播功能
swiperAuto() {
this.playTimer = setInterval(() => {
this.currentIndex++;
this.setTransition();
this.setTransform(-this.currentIndex * this.totalWidth);
this.currentScroll();
}, 2000);
},
stopTimer() {
clearInterval(this.playTimer);
},
},
mounted() {
// 由於網絡請求的圖片存在時間延遲,所以等 0.5s 讓圖片渲染出來
setTimeout(() => {
this.handleDom();
this.swiperAuto();
}, 500);
},
};
</script>
<style lang="less">
#hy-swiper {
position: relative;
overflow: hidden;
.swiper {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
// transform: translateX(-375px);
div {
float: left;
width: 100%;
flex-shrink: 0; //收縮因子為0 則可以使得所有圖片在同一行顯示
img {
width: 100%;
}
}
}
.swiper-circle {
position: absolute;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
ul li {
list-style: none;
float: left;
width: 12px;
height: 12px;
border-radius: 50%;
margin: 0 5px;
background-color: #fff;
}
.swiperItemActive {
background-color: var(--color-tint);
}
}
}
</style>
由於手機端是觸摸滑動的,因此與 pc 端略有不同,但是思路是一樣的。