Vue 使用 Swiper Element (WebComponent)
Swiper 是一個輪播圖套件,提供 JavaScript、React、Vue、Svelte 等方式使用。那為什麼不直接使用 Vue Component 呢?雖然目前還是能使用 Vue Componet,但官方有提到未來將會移除,並推薦使用 Swiper Element (WebComponent)。
安裝套件
npm install swiper
註冊
import { register } from 'swiper/element/bundle'
register()
使用
註冊 register() 後,就能使用 <swiper-container>、<swiper-slide> 這兩個 web component
<swiper-container>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
Vue Web Component 設定
預設 Vue 會將非原生 HTML tag 解析為 Vue Component,但實際上我們沒有以上兩個 Component,因此我們為了讓 Vue 知道哪些為自訂元素,需要額外做設定 compilerOptions.isCustomElement。
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: tag => tag.includes('swiper')
}
}
})
]
}
參數寫在 <swiper-container> 屬性上
寫在屬性上需要以 [key]-[subkey]="value" 的寫法,或是 Vue 可以用 v-bind,例如以下設定 pagination 的 hideOnClick。
<swiper-container
slides-per-view="3"
loop="true"
:pagination="{
hideOnClick: true
}"
>
<swiper-slide>Slide 1</swiper-slide>
...
</swiper-container>
參數太複雜也能使用 HTMLElement 作為傳遞
需要在 <swiper-container> 增加 init="false"
<script setup lang="ts">
import { register } from 'swiper/element'
register()
const params = {
slidesPerView: 1,
breakpoints: {
640: {
slidesPerView: 2,
},
1024: {
slidesPerView: 3,
}
}
}
const swiperEl = ref()
onMounted(() => {
swiperEl.value = document.querySelector('swiper-container')
if (swiperEl) {
Object.assign(swiperEl.value, params)
swiperEl.value?.initialize()
}
})
</script>
<template>
<swiper-container init="false"> ... </swiper-container>
</template>
取得 Swiper instance 操作 Methods
<script setup lang="ts">
...
const clickHandler = () => {
swiperEl.value?.swiper?.slideNext()
}
</script>
<template>
<swiper-container init="false"> ... </swiper-container>
<button @click="clickHandler">
Slide Next
</button>
</template>
加入模組 Modules
需要使用 modules 參數來加入模組
<script setup lang="ts">
import { register } from 'swiper/element'
import { Navigation, Pagination } from 'swiper/modules';
register()
const params = {
modules: [Navigation, Pagination],
injectStylesUrls: [
'swiper/element/css/navigation',
'swiper/element/css/pagination'
]
}
const swiperEl = ref()
onMounted(() => {
swiperEl.value = document.querySelector('swiper-container')
if (swiperEl) {
Object.assign(swiperEl.value, params)
swiperEl.value?.initialize()
}
})
</script>
<template>
<swiper-container init="false"> ... </swiper-container>
</template>
WARNING
但這時候發現依照官方的範例,injectStylesUrls 無法正常引入 styles
依照 issues 的解釋
Vite Vue 直接在 injectStylesUrls 使用 swiper/element/css/navigation,實際上會請求 http://localhost:5173/swiper/element/css/navigation 導致找不到。
正確使用方法
import { Navigation } from 'swiper/modules'
import NavigationStyle from 'swiper/element/css/navigation?url'
const params = {
modules: [Navigation],
injectStylesUrls: [NavigationStyle],
}
至於為什麼要加 ?url,可以參考 Vite - Static Asset Handling