はじめに
swiperを用いたスライダーの実装の記事はたくさんあったが、
サムネイル画像もスライダーにする実装ばかりでサムネイル画像を固定画像とするものが少なかったので
残しておきます。
環境
- MacOS
- yarn 1.22.17
- node v14.17.1
- vue 2.6.14
- vue-awesome-swiper 4.1.1
完成品
全体コード
<template>
<div class="room-swiper">
<Swiper ref="swiperRef" class="top" :options="swiperOption">
<SwiperSlide
v-for="(slider, index) in sliderContents"
:key="index"
class="slide"
>
<img class="image" :src="slider" />
</SwiperSlide>
</Swiper>
<div class="thumbs">
<div
v-for="(thumbs, index) in thumbsContents"
:key="index"
class="slide"
:class="{ '-active': index === activeIndex }"
>
<img class="image" :src="thumbs" @click="clickHandler(index)" />
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from '@nuxtjs/composition-api';
import SwiperClass from 'swiper';
import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
export default defineComponent({
components: {
Swiper,
SwiperSlide,
},
props: {
sliderContents: {
type: Array,
required: true,
},
},
setup() {
type SwiperModule = typeof Swiper & {
$swiper: SwiperClass;
initSwiper: () => void;
};
const swiperRef = ref<SwiperModule>();
const activeIndex = ref<number>(0);
// 上のスワイパーは画面読み込み時2番目が表示されているため下のサムネイルも初期選択が2番目になるようにしている
const thumbsContents = [
...props.sliderContents.slice(1),
props.sliderContents[0],
];
const swiperOption = {
loop: true,
loopedSlides: 3,
spaceBetween: 10,
slidesPerView: 3,
autoplay: {
delay: 5000,
disableOnInteraction: false,
},
on: {
slideChange: () => {
if (!swiperRef.value || !swiperRef.value.$swiper) return;
activeIndex.value = swiperRef.value.$swiper.realIndex;
},
},
};
const clickHandler = (index: number) => {
if (
!swiperRef.value ||
!swiperRef.value.$swiper ||
!swiperRef.value.$swiper.controller
)
return;
swiperRef.value?.$swiper.slideToLoop(index);
};
return {
swiperRef,
activeIndex,
swiperOptionTop,
clickHandler,
thumbsContents,
};
},
});
</script>
解説
スワイパー部分
propsで受け取ったsliderContents(画像の配列)をv-forで回しています。
また、optionを swiperOption
として渡しています。
Swiper
、SwiperSlide
の使い方に関しては以下を参考にしてください。
https://github.com/surmon-china/vue-awesome-swiper
<Swiper ref="swiperTop" class="top" :options="swiperOptionTop">
<SwiperSlide
v-for="(slider, index) in sliderContents"
:key="index"
class="slide"
>
<img class="image" :src="slider" />
</SwiperSlide>
</Swiper>
オプション
const swiperTop = ref<SwiperModule>();
const activeIndex = ref<number>(0);
const swiperOption = {
loop: true,
loopedSlides: 3,
spaceBetween: 10,
slidesPerView: 3,
autoplay: {
delay: 5000,
disableOnInteraction: false,
},
on: {
slideChange: () => {
if (!swiperTop.value || !swiperTop.value.$swiper) return;
activeIndex.value = swiperTop.value.$swiper.realIndex;
},
},
};
slideChange
オプションを指定することで、画像がスライドする時に発火してくれます。
realIndex
にはスライドしている画像のインデックス番号が入ります。
on: {
slideChange: () => {
if (!swiperTop.value || !swiperTop.value.$swiper) return;
activeIndex.value = swiperTop.value.$swiper.realIndex;
},
},
サムネイル
画像クリック時にclickHandler
を発火させています。
今回はcssを省いていますが、v-forで回しているindex番号とactiveIndexが一致した時にクラスをつけるというイメージです。
そのクラスにopacity
を指定すれば、それっぽくなると思います!
<div class="thumbs">
<div
v-for="(thumbs, index) in thumbsContents"
:key="index"
class="slide"
:class="{ '-active': index === activeIndex }"
>
<img class="image" :src="thumbs" @click="clickHandler(index)" />
</div>
</div>
const clickHandler = (index: number) => {
if (
!swiperTop.value ||
!swiperTop.value.$swiper ||
!swiperTop.value.$swiper.controller
)
return;
// 引数に指定したスライドに移動させる slideTo というメソッドを使って移動させる。loopの設定をしている場合はslideToLoop を使う
swiperTop.value?.$swiper.slideToLoop(index);
};
さいごに
サムネイル画像付きのスライダーはなんかかっこいいですね!!!