Swiperで動的なスライド形式に表示させたい!
投稿日: 2025年03月03日
オリアプで、スライド形式に表示させたくて今回はSwiperを使ってみたので、
皆さんにも共有したいと思います!
Swiperは、Webアプリやモバイルアプリでスライダー(カルーセル)を実装するための軽量かつ高機能なJavaScriptライブラリです。
他のライブラリに依存せず、JavaScriptの他にjQuery、React、Vue.jsでも使えます。
詳しくは、以下の公式ページをご覧ください。
以下、完成イメージです。(動画貼れないのでURL先で見てください)
AmazonとかzozotownのECサイトとかで、皆さんもよく見かけるスライド形式なやつです!
スライドして商品を眺められるアレです笑
手動もできますが、動的にもできるのでおしゃれです笑
まずは、インストール
$ npm install swiper
Swiperのスタイルシートのインポート
Swiperではデフォルトスタイルを適用するために、以下をインポートします。
これは、スライダーの基本的なデザインやアニメーションを適切に表示させるために必要です。
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
swiper/css
: Swiperの基本的なスタイルのみを含むスタイルシートとなります。
基本的なレイアウトを提供するものです。swiper/css/navigation
: Swiper全てのモジュール(ナビゲーション、ページネーション)のスタイルを含んでいます。
つまり、追加でスタイルシートをインポートしなくても、各機能が使える状態となります。swiper/css/pagination
: ページネーション機能に必要なスタイルのみを含むスタイルシートです。
ページネーション: スライドの下部などに配置されるドットや番号のことを指します。
ナビゲーション: スライダーの左右に配置される矢印のことです。
スタイルシート類
Swiperコンポーネントのインポート
Swiperを使用するために、必要なコンポーネントはライブラリをインポートします。
import { Swiper, SwiperSlide } from "swiper/react";
import { Autoplay, Navigation, Pagination } from "swiper/modules";
Swiper
コンポーネント: スライダー全体のコンテナとなるコンポーネントです。
スライダーの設定やオプションをこのコンポーネントに渡す感じです。SwiperSlide
コンポーネント:各スライドの内容を定義するためのコンポーネントです。
コンポーネントの小要素として配置し、スライドごとに異なるコンテンツを設定できます。Autoplay
モジュール: スライダーを自動的に再生するモジュールです。
例えば、数秒ごとに次のスライドへ自動的に切り替わるように設定できます。Navigation
モジュール: 先程紹介したナビゲーションのことで、スライダーの左右に配置し、「前へ」「次へ」とナビゲーションボタン(矢印)の機能を提供してくれます。
手動で、スライドが切り替わることができます。Pagination
モジュール:これも先程紹介したページネーションのことで、スライダーの下部に配置されるドットのことです。現在のスライドの全体の位置がどの辺りかを視覚的に示し、ユーザーが特定のスライドに直接移動することが可能です。
import React from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Autoplay, Navigation, Pagination } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
const MySlider = () => {
return (
<Swiper
modules={[Autoplay, Navigation, Pagination]}
spaceBetween={30}
slidesPerView={1}
loop={true}
autoplay={{ delay: 3000, disableOnInteraction: false }}
navigation
pagination={{ clickable: true }}
>
<SwiperSlide>
<img src="image1.jpg" alt="Slide 1" />
</SwiperSlide>
<SwiperSlide>
<img src="image2.jpg" alt="Slide 2" />
</SwiperSlide>
<SwiperSlide>
<img src="image3.jpg" alt="Slide 3" />
</SwiperSlide>
</Swiper>
);
};
export default MySlider;
ポイント
modules
プロパティで使用するモジュール(Autoplay
、Navigation
、Pagination
)を指定する
spaceBetween
はスライド間のスペースを指定する。
slidesPerView
は同時に表示させるスライドの枚数を指定。
loop
をtrue
にすると、スライドが最後に到達した後、最初のスライド戻り、ループし続ける。
autoplay
オプションで、自動再生を設定する。delay
は次のスライド画面に切り替わる時間を設定。disableOnInteraction
をfalse
にすると、ユーザーがスライドを操作しても自動再生が停止しない設定になる。
navigation
は先ほどの説明と同様です。
pagination
も説明は同様です。
以下は、投稿フォームで登録したカフェの情報を、最新情報とおすすめカフェ情報と項目で分けてスライド形式で表示させるコードです。
投稿が1つの情報しかない場合は、通常のカード形式にし、投稿が2個以上の場合はSwiperのオプション達(loop, nabigation, pagination)を使用してスライド形式にしてます。
"use client";
import React from "react";
import Image from "next/image";
import { Swiper, SwiperSlide } from "swiper/react";
import { Autoplay, Navigation, Pagination } from "swiper/modules";
import { Cafe } from "@/app/_types/Cafe";
import { timeAgo } from "../_utils/timeAgo";
import { RenderStars } from "../_utils/renderStars";
import "../../globals.css";
// Swiper のスタイルをインポート
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
type Props = {
cafes: Cafe[];
onClick: (cafes: Cafe) => void;
};
// 最新カフェ投稿の表示
export const LatestCafeList: React.FC<Props> = ({ cafes, onClick }) => {
if(cafes.length === 0) {
return <p className="mb-[100px] text-[min(13vw,25px)] font-bold text-custom-red">最新情報の投稿がありません</p>
}
return (
<div className="mt-[100px]">
<h1 className="font-bold text-[min(13vw,30px)] text-center">最新情報</h1>
<Swiper
className={`mx-auto py-10 mt-[100px] bg-beige-200 rounded-lg shadow-md overflow-hidden ${
cafes.length === 1 ? "max-w-[400px] h-[400px]" : "max-w-[800px] h-[400px]"
}`}
modules={[Autoplay, Navigation, Pagination]}
spaceBetween={10}
slidesPerView={Math.min(2, cafes.length)}
loop={cafes.length > 1} // スライドが2つ以上のときのみループ
autoplay={{
delay: 3000,
disableOnInteraction: false,
}}
navigation={cafes.length > 1} // 2つ以上のスライドがある場合のみナビゲーションを有効化
pagination={cafes.length > 1 ? { clickable: true } : false} // 2つ以上のスライドがある場合のみページネーションを有効化
watchOverflow={true} // スライドが1枚のときSwiperのレイアウト崩れを防ぐ
breakpoints={{
480: {
slidesPerView: 1,
spaceBetween: 10,
},
768: {
slidesPerView: 2,
spaceBetween: 20,
},
1024: {
slidesPerView: Math.min(3, cafes.length),
spaceBetween: 30,
},
}}
>
{cafes.map((cafe) => (
<SwiperSlide key={cafe.id}>
<div
className="bg-beige-200 rounded-lg shadow-md overflow-hidden"
onClick={() => onClick(cafe)}
>
<div className="relative w-full h-[200px]">
<Image
src={cafe.thumbnailImage}
alt={cafe.cafeName}
className="rounded-lg object-cover"
fill
/>
</div>
<div className="p-5 h-[200px]">
<h3 className="text-sm font-bold pt-2">{cafe.cafeName}</h3>
<p className="text-sm font-bold pt-10">
{timeAgo(cafe.createdAt || cafe.updatedAt)}
</p>
</div>
</div>
</SwiperSlide>
))}
</Swiper>
</div>
);
};
//おすすめカフェの表示
export const RecommendationCafeList: React.FC<Props> = ({ cafes, onClick }) => {
if(cafes.length === 0) {
return <p className="mt-[100px] text-[min(13vw,25px)] font-bold text-custom-red">おすすめカフェ情報の投稿がありません</p>
}
return (
<div className="mt-[200px] mb-[130px]">
<h1 className="font-bold text-[min(13vw,30px)] text-center">
おすすめのカフェ情報
</h1>
<Swiper
className={`mx-auto py-10 mt-[100px] bg-beige-200 rounded-lg shadow-md overflow-hidden ${
cafes.length === 1 ? "max-w-[400px] h-[400px]" : "max-w-[800px] h-[400px]"
}`}
modules={[Autoplay, Navigation, Pagination]}
spaceBetween={10}
slidesPerView={Math.min(2, cafes.length)}
loop={cafes.length > 1} // スライドが2つ以上のときのみループ
autoplay={{
delay: 3000,
disableOnInteraction: false,
}}
navigation={cafes.length > 1} // 2つ以上のスライドがある場合のみナビゲーションを有効化
pagination={cafes.length > 1 ? { clickable: true } : false} // 2つ以上のスライドがある場合のみページネーションを有効化
watchOverflow={true} // スライドが1枚のときSwiperのレイアウト崩れを防ぐ
breakpoints={{
480: {
slidesPerView: 1,
spaceBetween: 10,
},
768: {
slidesPerView: 2,
spaceBetween: 10,
},
1024: {
slidesPerView: Math.min(3, cafes.length),
spaceBetween: 20,
},
}}
>
{cafes.map((cafe) => (
<SwiperSlide key={cafe.id}>
<div
className="bg-beige-200 rounded-lg shadow-md overflow-hidden"
onClick={() => onClick(cafe)}//クリックされたカフェを渡す
>
<div className="relative w-full h-[200px]">
<Image
src={cafe.thumbnailImage}
alt={cafe.cafeName}
fill
className="rounded-lg object-cover"
/>
</div>
<div className="p-5 h-[200px]">
<h3 className="text-sm font-bold pt-5">{cafe.cafeName}</h3>
<p className="text-sm font-bold pt-5">
星評価: {RenderStars(cafe.starRating)}
</p>
<p className="text-sm font-bold pt-5">エリア {cafe.area}</p>
</div>
</div>
</SwiperSlide>
))}
</Swiper>
</div>
);
};
Swiperを使った、UIでおしゃれなスライドを表示させてみました。
興味がありましたら使ってみてはいかがでしょうか。