実際の現場で、swiper
を使用して
画像の切り替えを行う際、navigationボタンを押下した時に、
表示されている画像のテキストも切り替える実装に
かなり苦戦したため、備忘録として記載します。
初めに
swiperとは何ぞやという人は、下記の公式ページを参照ください。
それぞれ目的の合ったリンクを確認するのが良いと思います。
Vueの場合:swiper Vue.js Components
Nuxtの場合:Swiper Nuxt Modules
本題
ここでは、3つのコンポーネントを使用して、
子→親→子という形で、defineProps
及びdefineEmits
を
行います。
まず全体のソースコードはこちらになります。
親コンポーネント(index.vue)
/page/swiper/index.vue
<template>
<div>
<SwiperComponent @updateComment="updateComment" />
<CommentDisplay :comment="currentComment"/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const currentComment = ref<string>()
const updateComment = (newComment: string) => {
currentComment.value = newComment
}
</script>
子コンポーネント(SwiperComponent.vue)
/components/SwiperComponent.vue
<template>
<swiper
:modules="[Navigation]"
:slides-per-view="1"
@slideChange="onSlideChange"
:navigation="{
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}"
>
<swiper-slide v-for="image in images" :key="image.id">
<div>
<img :src="image.src" :alt="'Image ' + image.id" />
</div>
</swiper-slide>
</swiper>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</template>
<script setup lang="ts">
import 'swiper/css';
import 'swiper/css/navigation';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Navigation } from 'swiper/modules';
import { onMounted, ref } from 'vue'
interface SwiperInstance {
realIndex: number;
}
//data
const images = [
{
id: 1,
src: 'assets\img\カワイクテゴメンネ.jpg',
comment: 'This is the first image.'
},
{
id: 2,
src: 'assets\img\image_processing20200630-1-1rg32vr.jpg',
comment: 'This is the second image.'
},
{
id: 3,
src: 'assets\img\IMG_3490-1024x683.jpg',
comment: 'This is the third image.'
}
];
const emit = defineEmits(['updateComment'])
const onSlideChange = (swiper: SwiperInstance) => {
const currentComment = images[swiper.realIndex].comment
emit('updateComment', currentComment)
}
// 初期描画時のコメントを取得する
onMounted(() => {
emit('updateComment', images[0].comment)
})
</script>
<style scoped>
img {
width: 100%;
height: auto;
}
p {
text-align: center;
margin: 10px 0 0;
}
.swiper-button-next,
.swiper-button-prev {
color: #000;
cursor: pointer;
}
</style>
子コンポーネント(CommentDisplay.vue)
/components/CommentDisplay.vue
<template>
<dev>
<p>{{ props.comment }}</p>
</dev>
</template>
<script setup lang="ts">
const props = defineProps<{
comment: string | undefined
}>();
</script>
<style scoped>
p {
text-align: center;
margin: 10px 0 0;
}
</style>
1. 子コンポーネント(SwiperComponent.vue)について
子コンポーネントにswiper
を実装しています
import 'swiper/css';
import 'swiper/css/navigation';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Navigation } from 'swiper/modules';
各swiperをインポートして、'swiper/modules'
でナビゲーションのモジュールを設定する
<swiper
:modules="[Navigation]"
:slides-per-view="1"
@slideChange="onSlideChange"
:navigation="{
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}"
>
<swiper-slide v-for="image in images" :key="image.id">
<div>
<img :src="image.src" :alt="'Image ' + image.id" />
</div>
</swiper-slide>
</swiper>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
templateで実装する方法は上記の実装を行い、
:modules="[Navigation]
で、ナビゲーションのモジュールを提供して
ナビゲーションボタンを使ってスライドを切り替える機能を提供しています。
:modules
属性を設定して、使用するモジュールを指定し、ここでは[Navigation]
を指定してナビゲーション機能を有効にしています。
:slides-per-view="1"
は、一度表示されるスライドの数を指定します。
1
と設定したことで、一度に1つのスライドが表示される設定になります。
:navigation="{ nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' }"
は、カスタムナビゲーションボタンを設定します。
nextEl
とprevEl
プロパティを使って、次へボタンと前へボタンの要素を指定します。
今回の場合、.swiper-button-next
と.swiper-button-prev
はそれぞれ「次へ」ボタンと「前へ」ボタンのCSSセレクタを指します。
これにより、カスタムのナビゲーションボタンが機能するようになります。
const emit = defineEmits(['updateComment'])
const onSlideChange = (swiper: SwiperInstance) => {
const currentComment = images[swiper.realIndex].comment
emit('updateComment', currentComment)
}
onMounted(() => {
emit('updateComment', images[0].comment)
})
onSlideChange
関数の引数にswiper: SwiperInstance
を取得
SwiperInstance
の型定義は以下の設定にしておく
※ここでtypescriptの型を定義する
interface SwiperInstance {
realIndex: number;
}
以下のコードで、swiper.realIndex
を使って現在のスライドのインデックスを取得し、images
の配列から対応するcomment
を取得するようにする
const currentComment = images[swiper.realIndex].comment
最後にemit
で親コンポーネントにcommentを送信する
emit('updateComment', currentComment)
2. 親コンポーネント(index.vue)について
updateComment
でemitされたコメントをnewComment
に引数として持たせ、
currentComment
のref
にコメントを格納する
const currentComment = ref<string>()
const updateComment = (newComment: string) => {
currentComment.value = newComment
}
<CommentDisplay :comment="currentComment"/>
で別のコンポーネントにpropsする
<CommentDisplay :comment="currentComment"/>
3. 子コンポーネント(CommentDisplay.vue)について
親コンポーネントから渡されたpropsを設定し、<p>{{ props.comment }}</p>
でコメントを表示する
<script setup lang="ts">
const props = defineProps<{
comment: string | undefined
}>();
</script>
まとめ
ざっくりですが、swiperの仕組みが分かった経験でした
ほぼ実装コードはchatGPTに頼っての解決でしたが、chatGPTで的確な検索をするにはやはり知識を屈指して行うのが最短ルートだったなと感じました。
まだ分からないことも多々ありますが、自分自身で解決したことがとても嬉しいと感じたのが率直な感想です。
また、何かご指摘や誤った情報をしてしまっていましたらご指摘お願いいたします。。
公式の内容も確認しつつ行いましたが、ほぼchatGPTのおかげなので
今度は上手く調べられるようにしていきたいな、
(追伸. この実装を行うのに約3日くらいの時間を費やしたので今度はもう少し頑張りたい(´;ω;`))