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

閱讀時間約 21 分鐘

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>
raw-image

屬性說明

  • 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 結構

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,讓輪播內容範圍內縮,如果不做這個設定,輪播範圍會跟黃框一樣
raw-image

完成區塊設定後,再設定左右 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 直播班,看她與專題教練的討論紀錄,很開心她克服重重困難,完成了這份專題。
14會員
20內容數
從藝術領域轉職到前端工程師,喜歡書寫學習歷程和技術文件,掌握經驗與隨時提取的感覺很好。
留言0
查看全部
發表第一個留言支持創作者!
Ann Chou的沙龍 的其他內容
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Node 對我來說一直是很似懂非懂的概念,因為沒有實際可見的數字或字串實物可以觀察中間步驟,比起其他解題抽象許多。以下解題方法來自網友與 GPT 提供的答案,我想在本文中嘗試自己做視覺化圖解,說明 CodeWars - Can you get the loop ? 的解題思路。
JavaScript 套件,頁碼 Pagination.js 搭配 axios API 請求範例
分享這套功能齊全,視覺超級可愛還有響應式變化,教學文件又很容易閱讀的套件 Evo Calendar。 當初在製作 JS side project 時,想找一個與 VCalendar 視覺相近的套件,但多半都不合意。六角學院指派的 side project 教練也幫我找了另一個純 JS 的範例,也很
不喜歡 HTML 原生的時間選擇器外型嗎?試試看 flatpickr.js 吧! 以下是使用 flatpickr 做簡單的示例,以及 flatpickr 使用注意事項。
我依舊維持著修習 JS 的步伐,但我仍然覺得自己對 JS 的熟悉度不足。在 JS 班開課後,我藉由刷題庫和做 side project 專題,填補了課前的不自信感和知識焦慮。最終我們小組在 2.5 個月內開發了一個訂閱制電商網站的前後台,我也參加了 F2E week1 完賽,獲得銀級徽章
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Node 對我來說一直是很似懂非懂的概念,因為沒有實際可見的數字或字串實物可以觀察中間步驟,比起其他解題抽象許多。以下解題方法來自網友與 GPT 提供的答案,我想在本文中嘗試自己做視覺化圖解,說明 CodeWars - Can you get the loop ? 的解題思路。
JavaScript 套件,頁碼 Pagination.js 搭配 axios API 請求範例
分享這套功能齊全,視覺超級可愛還有響應式變化,教學文件又很容易閱讀的套件 Evo Calendar。 當初在製作 JS side project 時,想找一個與 VCalendar 視覺相近的套件,但多半都不合意。六角學院指派的 side project 教練也幫我找了另一個純 JS 的範例,也很
不喜歡 HTML 原生的時間選擇器外型嗎?試試看 flatpickr.js 吧! 以下是使用 flatpickr 做簡單的示例,以及 flatpickr 使用注意事項。
我依舊維持著修習 JS 的步伐,但我仍然覺得自己對 JS 的熟悉度不足。在 JS 班開課後,我藉由刷題庫和做 side project 專題,填補了課前的不自信感和知識焦慮。最終我們小組在 2.5 個月內開發了一個訂閱制電商網站的前後台,我也參加了 F2E week1 完賽,獲得銀級徽章
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
在著手開發一套程式時,會讓人覺得煩躁的考量點,其中一個讓人頭痛的,應該就是 UI 的設計跟串接了吧,究竟有沒有一個套件,能讓開發者能夠以一套語言,就能打遍天下呢?
Thumbnail
利用 gmailr 套件能夠有效地提升工作效率,透過 R 語言自動生成信件草稿,並允許個別修改與寄送,大幅減少出錯機率。本文介紹 gmailr 套件的安裝與帳號設定步驟,以及如何搜尋和讀取郵件以及撰寫郵件的相關方法。
Thumbnail
最近遇到了一個思考有點久的問題,如何將數值不同的樣品進行分組,同時每組的總和不能超越固定的上限值,且某些樣品不能被分在同一組。雖然規則並不困難,但是人工進行分組卻頗花時間,是不是有可能自動化處理這個步驟?如果有可能的話想要產出多個不同的分組方法,最後由人工選擇最佳的分組方式。
Thumbnail
上一篇文章說明了Pillow套件的基礎操作,這篇文章則會透過四個範例來示範如何利用Pillow製作簡單的GIF動畫。
Thumbnail
一早看著IThome的新聞發現到這個標題「📢 PyPI新帳號現需要啟用雙因素驗證才能執行管理操作」, 而近期幾乎都在接觸Python語言, 在Python的生態圈裡相信對於「pip install…」應該相當熟悉了吧! 但對於背後的平台相信我們不曾仔細去了解一番, 這好藉著這次的觀點也順便來介紹一
Thumbnail
本篇適合: > 剛開始學習 HTML / CSS ,對基本語法有了解的人 > 想要快速建立一個一頁式網站,但對 CSS 仍無法很活用的人 初始設定與 Bootstrap 中文版網頁使用 在過去在大學期間擔任助教的過程,常常有人問「Bootstrap」是什麼?一來我也不是什麼前端工程師,我一時也不太知
如有需要可以不用浪費效能重新將整個頁面重新載入,可以使用非同步的JS,使用動態載入資料
Thumbnail
ANKH原意為生命之鑰,是古埃及藝術用來代表生命的符號。Ankh Numpad延續Aaru的浮雕風格,摘錄了羅塞塔石碑的聖碑體倒數4~5排的部份文字,讓原本單純的Numpad鍵盤賦予更深一層的意涵,若再搭配TKL的Aaru,能讓按鍵功能更加完整,自然不能錯過啦~
Thumbnail
MotoGP油箱上長出翅膀背後的意義是?這都跟最新的空氣動力學提供更多的抓地力有關。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
在著手開發一套程式時,會讓人覺得煩躁的考量點,其中一個讓人頭痛的,應該就是 UI 的設計跟串接了吧,究竟有沒有一個套件,能讓開發者能夠以一套語言,就能打遍天下呢?
Thumbnail
利用 gmailr 套件能夠有效地提升工作效率,透過 R 語言自動生成信件草稿,並允許個別修改與寄送,大幅減少出錯機率。本文介紹 gmailr 套件的安裝與帳號設定步驟,以及如何搜尋和讀取郵件以及撰寫郵件的相關方法。
Thumbnail
最近遇到了一個思考有點久的問題,如何將數值不同的樣品進行分組,同時每組的總和不能超越固定的上限值,且某些樣品不能被分在同一組。雖然規則並不困難,但是人工進行分組卻頗花時間,是不是有可能自動化處理這個步驟?如果有可能的話想要產出多個不同的分組方法,最後由人工選擇最佳的分組方式。
Thumbnail
上一篇文章說明了Pillow套件的基礎操作,這篇文章則會透過四個範例來示範如何利用Pillow製作簡單的GIF動畫。
Thumbnail
一早看著IThome的新聞發現到這個標題「📢 PyPI新帳號現需要啟用雙因素驗證才能執行管理操作」, 而近期幾乎都在接觸Python語言, 在Python的生態圈裡相信對於「pip install…」應該相當熟悉了吧! 但對於背後的平台相信我們不曾仔細去了解一番, 這好藉著這次的觀點也順便來介紹一
Thumbnail
本篇適合: > 剛開始學習 HTML / CSS ,對基本語法有了解的人 > 想要快速建立一個一頁式網站,但對 CSS 仍無法很活用的人 初始設定與 Bootstrap 中文版網頁使用 在過去在大學期間擔任助教的過程,常常有人問「Bootstrap」是什麼?一來我也不是什麼前端工程師,我一時也不太知
如有需要可以不用浪費效能重新將整個頁面重新載入,可以使用非同步的JS,使用動態載入資料
Thumbnail
ANKH原意為生命之鑰,是古埃及藝術用來代表生命的符號。Ankh Numpad延續Aaru的浮雕風格,摘錄了羅塞塔石碑的聖碑體倒數4~5排的部份文字,讓原本單純的Numpad鍵盤賦予更深一層的意涵,若再搭配TKL的Aaru,能讓按鍵功能更加完整,自然不能錯過啦~
Thumbnail
MotoGP油箱上長出翅膀背後的意義是?這都跟最新的空氣動力學提供更多的抓地力有關。