2024-04-08|閱讀時間 ‧ 約 39 分鐘

【套件筆記 - Vue】輪播 Swiper.js

Swiper.js 是一個功能齊全的輪播套件,除了輪播外,也可以客製化導航按鈕和頁碼等細項。目前支持 JS、React、Vue。我的 Vue3 專題中也有使用這套套件呈現,但因為 Swiper.js Vue 版是由 Composition API 寫成,但我當時只會 Options API,花了很多時間了解撰寫方式。今天目標就是介紹 Swiper.js 在 Vue3 Options API 的用法和元件化小撇步。

今日目標:Swiper 複用元件

今日目標:Swiper 複用元件


目標功能

  1. 網頁每次顯示 3 則,768px 以下顯示 1 則
  2. 輪播時以更新 1 則為單位
  3. 可自動播放:Autoplay(自動播放)
  4. 可使用頁碼操作:Pagination(頁碼)
  5. 可使用導航切換上下頁:Navigation(上下一則導航)
  6. 輪播至最後一筆,會自動同方向重複播放:Loop(迴圈)
  7. 輪播元件可以重複使用,並秀出不同類別內容


一、官網資源/安裝

--- 2024/04/08 更新:請裝這個 ​------
npm i swiper@10.3.1

--- 舊文請忽略 ​------
npm i swiper@8.0.0

是的沒錯~ 雖然現在 Swiper 版本已經是 11 了,但 Options API 在版本 8 才不會出錯(2024/04/08 更新:Swiper 10.3.1 也可以)。我的使用經驗是不管是否為同一個 swiper 元件,重複在同一個頁面使用沒有問題。但如果在不同頁面中使用,navigation(上/下一張)的導航就會失效,只有降版沒有問題,可能跟 Swiper 後期版本是用 Composition api 來撰寫有關。我個人是習慣各版本文件搭配著看,雖然中文翻譯版已經很舊了,但是初學時的好利器。實作時也推薦大家先從 11 的 Demos 尋找範例開始,比較好入手。



二、建立元件

1. 引入方法

建立元件文件 SwiperComponent.vue。

官網提到:By default Swiper Vue uses core version of Swiper (without any additional modules). If you want to use Navigation, Pagination and other modules, you have to install them first.

所以像是 Autoplay(自動播放)、Pagination(頁碼)、Navigation(上下一則導航)都是要額外引入的。

<script>
// import Swiper js
import { Swiper, SwiperSlide } from 'swiper/vue'
// Swiper 8 這樣寫 ↓
import { Autoplay, Pagination, Navigation } from 'swiper'
// Swiper 10 這樣寫 ↓
import { Navigation, Pagination, Autoplay } from 'swiper/modules'

// Import Swiper stylesimport 'swiper/css'
import 'swiper/css/pagination'
import 'swiper/css/navigation'

export default{
data () {
return {
data: ..., // 你要渲染的資料
modules: [Autoplay, Pagination, Navigation] // 額外引入的 modules
}
},
components: {
Swiper,
SwiperSlide
}
}
</script>

2. 撰寫 HTML

// swiper 輪播主體,設置都要在 Swiper 標籤範圍內才會生效​
<Swiper
:slidesPerView="1"
:breakpoints="{
768: {slidesPerView: 3}
}"
:spaceBetween="30"
:pagination="{clickable: true,}"
:navigation="true"
:loop="true"
:autoplay="{
delay: 2500,
disableOnInteraction: false
}"
:modules="modules"
> 

// 在 swiper-slide 裡面放入要呈現的圖片和標題,每個 swiper-slide 都是獨立的區塊
<swiper-slide v-for="item in data" :key="item">
<img :src="item.img" alt="item.title">
<h3>{{item.title}}</h3>
</swiper-slide>

</Swiper>

屬性說明

  • slidesPerView:每次輪播更換則數。
  • breakpoints:RWD 響應式斷點,但是請注意只有文件中提到的屬性才能用 RWD,其他操作只能用 CSS 或 JS 實現。在這裡的設定是 slidesPerView 在 768px 以上顯示 3 則,以下顯示 1 則。
  • spaceBetween:每則輪播間距,如果想做文字跑馬燈,也可以設定成 auto,讓他自動計算。
  • pagination:在此設定為可以使用點選操作的,pagination 還有外觀選項
  • navigation:上下一則導航,如果要使用則設為 true,文章後面會再介紹如何客製化樣式。
  • loop:播放至最後一筆時,能維持同一方向從第一筆繼續播放。如果不設定,則整個 swiper 會先逆向回到第一筆,才開始輪播。
  • autoplay:自動輪播,在此設定 2500 毫秒輪播,滑鼠互動時,輪播不會暫停計秒。

詳細可以參考官方文件,內容有每個屬性的預設值和調整方法。

3. 在父元件使用

<template>
<div class="container"> // swiper 必須設定顯示區域尺寸
<SwiperComponent></SwiperComponent>
</div>
</template>

<script>
// 引入 swiper 元件​
import SwiperComponent from '@/components/SwiperComponent.vue'

export default {
components: {
SwiperComponent
}
}
</script>

完成到這裡就可以使用啦!很方便又快速~



三、元件複用

1. 元件複用的好處

  • 減少重複程式碼
  • 調整只需要更動元件,避免修改四散的程式碼,較好維護

2. 實作方法

Vue 元件使用的資料可以由內部生成外部傳入,我們要同時運用這兩個技巧。
  1. 先在 SwiperComponent.vue 中建立我們要顯示資料的欄位,以本文目標範例圖來說,首先是每個 swiper 區塊的標題。
    我們先從父元件輸入外部資料試試看,於元件引用處上建立外部屬性 adCategoryTitle,並寫入要呈現的字串標題。
// 父元件​
<template>
<div class="container">
<SwiperComponent adCategoryTitle="猜你喜歡吃甜甜"></SwiperComponent>
<SwiperComponent adCategoryTitle="邀請你來嚐口感"></SwiperComponent>
<SwiperComponent adCategoryTitle="美味氣氛隨你加"></SwiperComponent>
</div>
</template>
  1. 回到 swiper 元件,將剛才設定的外部屬性名稱填入,就完成了。
// SwiperComponent.vue​
<template>
<div>
<h2>{{ adCategoryTitle }}</h2> // 使用資料
<Swiper...</Swiper>
</div>
</template>

<script>
export default {
... 略​
props: ['adCategoryTitle'] // 由 props 接收外部傳入資料
}
</sctipt>
  1. 但通常複用元件不僅只有標題變化,輪播內容也要不同,所以我們可以再回頭修改上面的程式碼。
    以下 swiper 元件運作邏輯是:
    .將父元件傳入的文字屬性化,從中文標題改成分類。
    .swiper 元件建立屬性對應的標題 adTitle,結合上一個步驟,就可以利用傳入資料對應獲取的中文標題了,這可以避免中文字要修改時父子元件都要更動的問題。
    .父元件渲染時,每碰到 swiper 元件都會啟動 mounted 獲取產品資料 getProducts()
    getProducts() 也是根據外部傳入資料,獲取對應要顯示的產品內容。
// 父元件
<template>
<div class="container">
<SwiperComponent adCategoryTitle="sweet"></SwiperComponent>
<SwiperComponent adCategoryTitle="taste"></SwiperComponent>
<SwiperComponent adCategoryTitle="spices"></SwiperComponent>
</div>
</template>
// SwiperComponent.vue​
export default {
props: ['adCategoryTitle'],
data () {
return {
allProducts: [],
adTitle: {
sweet: '猜你喜歡吃甜甜',
taste: '邀請你來嚐口感',
spices: '美味氣氛隨你加'
},
modules: [Autoplay, Pagination, Navigation]
}
},
methods: {
// 獲取產品
getProducts () {
if (adCategoryTitle === "sweet"){ // 根據傳入 props 獲取對應資料​
...
this.allProducts = response
}else if (adCategoryTitle === "taste"){...}
}
},
mounted () {
this.getProducts()
},
components: {
Swiper,
SwiperSlide
}
}
</script>



四、客製化 swiper 樣式

1. 客製化 navigation

swiper 本身動作就綁定在原生 CSS 樣式上,不需要額外寫 idclass 使用 DOM 綁定。以下 .swiper-button-next.swiper-button-prev 都是原生設定,藉由這兩項樣式調整 CSS,就可以客製化外觀了。

如果 navigation 要 RWD 響應式顯示,也是藉由 CSS 設定。

// SwiperComponent.vue​
// 原本我們在 <Swiper> 標籤中的設定
<Swiper :navigation="true">
<SwiperSlide>...</SwiperSlide>
</Swiper>

// 修改成以下設定​
<Swiper :navigation="{
nextEl: '.swiper-button-next', // 下一則
prevEl: '.swiper-button-prev' // 上一則
}">
<SwiperSlide>...</SwiperSlide>
// 因為要客製化 button,所以額外新增 DOM 在 <Swiper> 內,並套用原生 class 樣式
<button class="swiper-button-next"></button>
<button class="swiper-button-prev"></button>
</Swiper>
// SwiperComponent.vue​
// 請依你的專案微調 css 數值​
<style lang="scss" scoped>
// 替換成客製化 icon 的方法​
.swiper-button-next{
// 插入你想使用的 icon 即設定尺寸
background: url("...") no-repeat center;
background-size: 40px 40px;

// 隱藏原生的藍色箭頭
text-indent: 101%;
white-space: nowrap;
overflow: hidden;
width: 40px;
height: 40px;
}

// 僅替換原生箭頭顏色的方法
.swiper-button-prev {
// 使用 color 就可以更換箭頭顏色​
color: $red;
}
</style>

2. navigation 在 Swiper 元件範圍外顯示的方法

swiper 預設的 navigation 是在 .swiper 範圍內的。如果要讓 navigation(藍框)像下圖超出在 .swiper(紅框)範圍外,我們要先來釐清它的 CSS。

swiper 結構

HTML 中 <Swiper> 生成的範圍就是途中右側使用 .swiper 樣式的區域範圍,它本身有 position-relativeoverflow-hidden 的設定,所以我們可以發現:

  • 查看 .swiper-button-next.swiper-button-prev,發現原生帶有 position-absolute 樣式,所以可以透過 top/right... 等方法定位。
  • 如果直接移動 navigation 位置,會發現超出 .swiper 的部分會被隱藏,所以我們要針對區域尺寸做更改。
// SwiperComponent.vue​
<Swiper class="product-swiper">  // 新增一個樣式
...
</Swiper>
<style lang="scss" scoped>
// 由於我的預設是 768px 以內不顯示 navigation 所以做了 RWD 設定
// 如果 navigation 一直存在,只要參考 @media{} 內的程式碼就好​
:deep(.product-swiper) {
margin: auto;
padding: 0;

@media (min-width: 768px) {
// 因為我的 navigation 尺寸是 40x40,我希望能凸出顯示一半,所以設定 20px
margin: 0 -20px !important;
padding: 0 20px !important;
}
}
</style>

我們可以從下圖理解 padding 和 margin 合作關係。

  • 紅框是我們要限縮內容顯示的範圍
  • padding 20px,將 .swiper overflow-hidden 的範圍左右撐開
  • margin -20px,讓輪播內容範圍內縮,如果不做這個設定,輪播範圍會跟黃框一樣

完成區塊設定後,再設定左右 navigaiton button 的位置就完成了~

<style lang="scss" scoped>
// 因為原生 swiper navigation​ 就帶有 position-absolute 樣式,所以直接定義位置
.swiper-button-next {
top: 50%;
right: 0px;
...
}
.swiper-button-prev {
top: 50%;
left: 0px;
...
}
</style>

3. 客製化 pagination

pagination 也可以使用原生的 .swiper-pagination 修改。
例如以下做了只有 768px 以下才顯示、更改 pagination 顏色。

/* swiper 顯示區域尺寸 */
// 其實 pagination 的位置是仰賴 swiper-wrapper​ 區塊
// pagintaion 預設自動貼合 swiper-wrapper 區塊底端,所以要藉由 margin-bottom 把區塊撐大
.swiper-wrapper {
margin-bottom: 36px;

@media (min-width: 768px) {
margin-bottom: 0rem;
}
}

/*Swiper 頁碼導覽*/
.swiper-pagination {
display: inline-block;

@media (min-width: 768px) {
display: none;
}

&-bullet {
background: #787878;
}

&-bullet-active {
background: #333333;
}
}


五、結尾

  1. 當初在 swiper vue 上卡了很久,感謝 Billy 助教提供指點,告訴我要換成 swiper 8 才能避免錯誤。
  2. (2024/04/08 更新)
    感謝好同學聿凌提問 Swiper 10 能否運行,經過測試也沒問題!
    附上這位超認真同學的專題 RepoPages,這是一個南部旅遊方案電商,整個平台和 JSON Server 資料庫都是她獨力開發完成的。從 JS 直播班到 Vue 直播班,看她與專題教練的討論紀錄,很開心她克服重重困難,完成了這份專題。
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.