Swiper.js 是一個功能齊全的輪播套件,除了輪播外,也可以客製化導航按鈕和頁碼等細項。目前支持 JS、React、Vue。我的 Vue3 專題中也有使用這套套件呈現,但因為 Swiper.js Vue 版是由 Composition API 寫成,但我當時只會 Options API,花了很多時間了解撰寫方式。今天目標就是介紹 Swiper.js 在 Vue3 Options API 的用法和元件化小撇步。
--- 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 尋找範例開始,比較好入手。
建立元件文件 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>
// 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>
屬性說明:
詳細可以參考官方文件,內容有每個屬性的預設值和調整方法。
<template>
<div class="container"> // swiper 必須設定顯示區域尺寸
<SwiperComponent></SwiperComponent>
</div>
</template>
<script>
// 引入 swiper 元件
import SwiperComponent from '@/components/SwiperComponent.vue'
export default {
components: {
SwiperComponent
}
}
</script>
完成到這裡就可以使用啦!很方便又快速~
Vue 元件使用的資料可以由內部生成與外部傳入,我們要同時運用這兩個技巧。
// 父元件
<template>
<div class="container">
<SwiperComponent adCategoryTitle="猜你喜歡吃甜甜"></SwiperComponent>
<SwiperComponent adCategoryTitle="邀請你來嚐口感"></SwiperComponent>
<SwiperComponent adCategoryTitle="美味氣氛隨你加"></SwiperComponent>
</div>
</template>
// SwiperComponent.vue
<template>
<div>
<h2>{{ adCategoryTitle }}</h2> // 使用資料
<Swiper...</Swiper>
</div>
</template>
<script>
export default {
... 略
props: ['adCategoryTitle'] // 由 props 接收外部傳入資料
}
</sctipt>
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 本身動作就綁定在原生 CSS 樣式上,不需要額外寫 id
或 class
使用 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>
swiper 預設的 navigation 是在 .swiper
範圍內的。如果要讓 navigation(藍框)像下圖超出在 .swiper
(紅框)範圍外,我們要先來釐清它的 CSS。
HTML 中 <Swiper>
生成的範圍就是途中右側使用 .swiper
樣式的區域範圍,它本身有 position-relative
和 overflow-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 合作關係。
.swiper
overflow-hidden
的範圍左右撐開完成區塊設定後,再設定左右 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>
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;
}
}