Skip to content

Commit

Permalink
feat(swiper): 新增《Swiper》菜单模块
Browse files Browse the repository at this point in the history
  • Loading branch information
baiwumm committed Jan 20, 2025
1 parent c210bba commit 2377cbd
Show file tree
Hide file tree
Showing 12 changed files with 527 additions and 6 deletions.
12 changes: 11 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"technical-document":"Technical Document",
"nextjs":"Next.js Document",
"heroui":"Heroui Document",
"prisma":"Prisma Document"
"prisma":"Prisma Document",
"swiper":"Swiper"
},
"Pages":{
"internationalization":{
Expand Down Expand Up @@ -71,6 +72,15 @@
"icon":"Icon",
"iconTip":"Enter the icon name, for example, ri:home-line",
"redirect":"Redirect"
},
"swiper":{
"cube":"Cube",
"flip":"Flip",
"card":"Card Effect",
"coverflow":"3d Effect",
"thumbnail":"Thumbnail",
"creative":"Creative",
"visual":"Horizontal loop focus picture display"
}
},
"Global":{
Expand Down
12 changes: 11 additions & 1 deletion messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"technical-document":"技术文档",
"nextjs":"Next.js 文档",
"heroui":"Heroui 文档",
"prisma":"Prisma 文档"
"prisma":"Prisma 文档",
"swiper":"Swiper"
},
"Pages":{
"internationalization":{
Expand Down Expand Up @@ -71,6 +72,15 @@
"icon":"图标",
"iconTip":"请填写图标名称,如:ri:home-line",
"redirect":"重定向地址"
},
"swiper":{
"cube":"方块",
"flip":"翻转",
"card":"卡片特效",
"coverflow":"3d 流翻转",
"thumbnail":"缩略图",
"creative":"创意效果",
"visual":"横向循环焦点图片展示"
}
},
"Global":{
Expand Down
26 changes: 26 additions & 0 deletions src/app/features/swiper/components/CardSwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* @Author: 白雾茫茫丶<baiwumm.com>
* @Date: 2025-01-20 15:12:46
* @LastEditors: 白雾茫茫丶<baiwumm.com>
* @LastEditTime: 2025-01-20 16:02:37
* @Description: 卡片特效
*/
import 'swiper/css/effect-cards';

import { Image } from '@heroui/react';
import { EffectCards } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';

import { getRandomImg } from '@/lib/utils';
export default function CardSwiper() {
const imgs = getRandomImg(8) as string[];
return (
<Swiper effect="cards" grabCursor loop modules={[EffectCards]} className="w-60 h-80">
{imgs.map((src: string, i: number) => (
<SwiperSlide key={src + i}>
<Image src={src} alt="CardSwiper" removeWrapper className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
);
}
45 changes: 45 additions & 0 deletions src/app/features/swiper/components/CoverflowSwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* @Author: 白雾茫茫丶<baiwumm.com>
* @Date: 2025-01-20 15:31:30
* @LastEditors: 白雾茫茫丶<baiwumm.com>
* @LastEditTime: 2025-01-20 15:57:02
* @Description: 3d 流翻转
*/
import 'swiper/css/effect-coverflow';
import 'swiper/css/pagination';

import { Image } from '@heroui/react';
import { EffectCoverflow, Pagination } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';

import { getRandomImg } from '@/lib/utils';
export default function CoverflowSwiper() {
const imgs = getRandomImg(8) as string[];
return (
<Swiper
effect="coverflow"
grabCursor
centeredSlides
slidesPerView="auto"
coverflowEffect={{
rotate: 50,
stretch: 0,
depth: 100,
modifier: 1,
slideShadows: true,
}}
loop
pagination={{
clickable: true,
}}
modules={[EffectCoverflow, Pagination]}
className="w-full"
>
{imgs.map((src: string, i: number) => (
<SwiperSlide key={src + i} className="!w-80 !h-80">
<Image src={src} alt="CoverflowSwiper" removeWrapper className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
);
}
43 changes: 43 additions & 0 deletions src/app/features/swiper/components/CreativeSwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* @Author: 白雾茫茫丶<baiwumm.com>
* @Date: 2025-01-20 16:08:04
* @LastEditors: 白雾茫茫丶<baiwumm.com>
* @LastEditTime: 2025-01-20 16:55:30
* @Description: 创意效果
*/
import 'swiper/css/effect-creative';
import 'swiper/css/pagination';

import { Image } from '@heroui/react';
import { EffectCreative, Pagination } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';
import type { CreativeEffectOptions } from 'swiper/types';

import { getRandomImg } from '@/lib/utils';

type CreativeSwiperProps = {
creativeEffect: CreativeEffectOptions;
};
export default function CreativeSwiper({ creativeEffect = {} }: CreativeSwiperProps) {
const imgs = getRandomImg(8) as string[];
return (
<Swiper
effect="creative"
grabCursor
centeredSlides
loop
creativeEffect={creativeEffect}
pagination={{
clickable: true,
}}
modules={[EffectCreative, Pagination]}
className="w-80 h-60"
>
{imgs.map((src: string, i) => (
<SwiperSlide key={src + i}>
<Image src={src} alt="CreativeSwiper" removeWrapper className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
);
}
42 changes: 42 additions & 0 deletions src/app/features/swiper/components/CubeSwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* @Author: 白雾茫茫丶<baiwumm.com>
* @Date: 2025-01-20 13:42:53
* @LastEditors: 白雾茫茫丶<baiwumm.com>
* @LastEditTime: 2025-01-20 14:24:57
* @Description: 方块
*/
import 'swiper/css/effect-cube';
import 'swiper/css/pagination';

import { Image } from '@heroui/react';
import { EffectCube, Pagination } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';

import { getRandomImg } from '@/lib/utils';
export default function CubeSwiper() {
const imgs = getRandomImg(8) as string[];
return (
<Swiper
effect="cube"
grabCursor
cubeEffect={{
shadow: true,
slideShadows: true,
shadowOffset: 20,
shadowScale: 0.94,
}}
loop
pagination={{
clickable: true,
}}
modules={[EffectCube, Pagination]}
className="w-80 h-80"
>
{imgs.map((src: string, i: number) => (
<SwiperSlide key={src + i}>
<Image src={src} alt="CubeSwiper" removeWrapper className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
);
}
36 changes: 36 additions & 0 deletions src/app/features/swiper/components/FlipSwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* @Author: 白雾茫茫丶<baiwumm.com>
* @Date: 2025-01-20 15:03:00
* @LastEditors: 白雾茫茫丶<baiwumm.com>
* @LastEditTime: 2025-01-20 15:04:53
* @Description: 翻转
*/
import 'swiper/css/effect-flip';
import 'swiper/css/pagination';
import 'swiper/css/navigation';

import { Image } from '@heroui/react';
import { EffectFlip, Navigation, Pagination } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';

import { getRandomImg } from '@/lib/utils';
export default function FlipSwiper() {
const imgs = getRandomImg(8) as string[];
return (
<Swiper
effect="flip"
grabCursor
loop
navigation
pagination={{ clickable: true }}
modules={[EffectFlip, Pagination, Navigation]}
className="w-80 h-80"
>
{imgs.map((src: string, i: number) => (
<SwiperSlide key={src + i}>
<Image src={src} alt="FlipSwiper" removeWrapper className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
);
}
61 changes: 61 additions & 0 deletions src/app/features/swiper/components/ThumbnailSwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* @Author: 白雾茫茫丶<baiwumm.com>
* @Date: 2025-01-20 15:44:49
* @LastEditors: 白雾茫茫丶<baiwumm.com>
* @LastEditTime: 2025-01-20 16:01:58
* @Description: 缩略图
*/
import 'swiper/css/free-mode';
import 'swiper/css/navigation';
import 'swiper/css/thumbs';

import { Image } from '@heroui/react';
import { useState } from 'react';
import { FreeMode, Navigation, Thumbs } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';
import type { Swiper as SwiperClass } from 'swiper/types';

import { getRandomImg } from '@/lib/utils';
export default function ThumbnailSwiper() {
const imgs = getRandomImg(20) as string[];
const [thumbsSwiper, setThumbsSwiper] = useState<SwiperClass>();

const onThumbsSwiper = (swiper: SwiperClass) => {
setThumbsSwiper(swiper);
};
return (
<div className="h-80">
<Swiper
loop
spaceBetween={10}
navigation
modules={[FreeMode, Navigation, Thumbs]}
thumbs={{ swiper: thumbsSwiper }}
className="w-full h-4/5"
>
{imgs.map((src: string, i: number) => (
<SwiperSlide key={src + i}>
<Image src={src} removeWrapper alt="CubeSwiper" className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
{/* 缩略图 */}
<Swiper
loop
spaceBetween={10}
slidesPerView={5}
freeMode
watchSlidesProgress
modules={[FreeMode, Navigation, Thumbs]}
className="thumbs-swiper h-1/5 !pt-2.5"
onSwiper={onThumbsSwiper}
>
{imgs.map((src: string, i: number) => (
<SwiperSlide key={src + i}>
<Image src={src} alt="CubeSwiper" removeWrapper className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
</div>
);
}
72 changes: 72 additions & 0 deletions src/app/features/swiper/components/VisualSwiper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* @Author: 白雾茫茫丶<baiwumm.com>
* @Date: 2025-01-20 17:09:09
* @LastEditors: 白雾茫茫丶<baiwumm.com>
* @LastEditTime: 2025-01-20 17:14:39
* @Description: 横向循环焦点图片展示
*/
import 'swiper/css/navigation';
import 'swiper/css/pagination';

import { Image } from '@heroui/react';
import { Autoplay, Navigation, Pagination } from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';
import type { Swiper as SwiperClass } from 'swiper/types';

import { getRandomImg } from '@/lib/utils';
export default function VisualSwiper() {
const imgs = getRandomImg(20) as string[];

// 事件将在Swiper进度更改时激发,作为参数,它接收的进度始终从0到1
const onProgress = (swiper: SwiperClass) => {
for (let i = 0; i < swiper.slides.length; i += 1) {
const slide = swiper.slides[i];
const slideProgress = slide.progress;
let modify = 1;
if (Math.abs(slideProgress) > 1) {
modify = (Math.abs(slideProgress) - 1) * 0.3 + 1;
}
const translate = `${slideProgress * modify * 260}px`;
const scale = 1 - Math.abs(slideProgress) / 5;
const zIndex = 999 - Math.abs(Math.round(10 * slideProgress));
slide.style.transform = `translateX(${translate}) scale(${scale})`;
slide.style.zIndex = `${zIndex}`;
slide.style.opacity = '1';
if (Math.abs(slideProgress) > 3) {
slide.style.opacity = '0';
}
}
};

// 事件将在每次swiper启动动画时触发。接收当前转换持续时间(以ms为单位)作为参数
const setTransition = (swiper: SwiperClass, transition: number) => {
for (let i = 0; i < swiper.slides.length; i += 1) {
const slide = swiper.slides[i];
slide.style.transition = `${transition}ms`;
}
};
return (
<Swiper
watchSlidesProgress
slidesPerView="auto"
centeredSlides
loop
loopAdditionalSlides={5}
autoplay
navigation
modules={[Navigation, Autoplay, Pagination]}
pagination={{
clickable: true,
}}
onProgress={onProgress}
onSetTransition={setTransition}
className="w-full !pb-10"
>
{imgs.map((src: string, i: number) => (
<SwiperSlide key={src + i} className="!w-[600px] !h-[450px]">
<Image src={src} alt="CubeSwiper" removeWrapper className="w-full h-full object-cover" radius="sm" />
</SwiperSlide>
))}
</Swiper>
);
}
11 changes: 11 additions & 0 deletions src/app/features/swiper/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.thumbs-swiper {
.swiper-slide {
height: 100%;
opacity: 0.4;
transition: .3s all;
cursor: pointer;
}
.swiper-slide-thumb-active {
opacity: 1;
}
}
Loading

0 comments on commit 2377cbd

Please sign in to comment.