From 2377cbd876b3d38dc8bfd89731c1caf1182cfd5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E8=8C=AB=E8=8C=AB=E4=B8=B6?= Date: Mon, 20 Jan 2025 17:17:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(swiper):=20=E6=96=B0=E5=A2=9E=E3=80=8ASwip?= =?UTF-8?q?er=E3=80=8B=E8=8F=9C=E5=8D=95=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en.json | 12 +- messages/zh.json | 12 +- .../features/swiper/components/CardSwiper.tsx | 26 +++ .../swiper/components/CoverflowSwiper.tsx | 45 +++++ .../swiper/components/CreativeSwiper.tsx | 43 +++++ .../features/swiper/components/CubeSwiper.tsx | 42 +++++ .../features/swiper/components/FlipSwiper.tsx | 36 ++++ .../swiper/components/ThumbnailSwiper.tsx | 61 +++++++ .../swiper/components/VisualSwiper.tsx | 72 ++++++++ src/app/features/swiper/index.scss | 11 ++ src/app/features/swiper/page.tsx | 165 ++++++++++++++++++ src/middleware.ts | 8 +- 12 files changed, 527 insertions(+), 6 deletions(-) create mode 100644 src/app/features/swiper/components/CardSwiper.tsx create mode 100644 src/app/features/swiper/components/CoverflowSwiper.tsx create mode 100644 src/app/features/swiper/components/CreativeSwiper.tsx create mode 100644 src/app/features/swiper/components/CubeSwiper.tsx create mode 100644 src/app/features/swiper/components/FlipSwiper.tsx create mode 100644 src/app/features/swiper/components/ThumbnailSwiper.tsx create mode 100644 src/app/features/swiper/components/VisualSwiper.tsx create mode 100644 src/app/features/swiper/index.scss create mode 100644 src/app/features/swiper/page.tsx diff --git a/messages/en.json b/messages/en.json index db5e2f7..dce45f2 100644 --- a/messages/en.json +++ b/messages/en.json @@ -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":{ @@ -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":{ diff --git a/messages/zh.json b/messages/zh.json index 34a62f6..696217f 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -16,7 +16,8 @@ "technical-document":"技术文档", "nextjs":"Next.js 文档", "heroui":"Heroui 文档", - "prisma":"Prisma 文档" + "prisma":"Prisma 文档", + "swiper":"Swiper" }, "Pages":{ "internationalization":{ @@ -71,6 +72,15 @@ "icon":"图标", "iconTip":"请填写图标名称,如:ri:home-line", "redirect":"重定向地址" + }, + "swiper":{ + "cube":"方块", + "flip":"翻转", + "card":"卡片特效", + "coverflow":"3d 流翻转", + "thumbnail":"缩略图", + "creative":"创意效果", + "visual":"横向循环焦点图片展示" } }, "Global":{ diff --git a/src/app/features/swiper/components/CardSwiper.tsx b/src/app/features/swiper/components/CardSwiper.tsx new file mode 100644 index 0000000..8088664 --- /dev/null +++ b/src/app/features/swiper/components/CardSwiper.tsx @@ -0,0 +1,26 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 15:12:46 + * @LastEditors: 白雾茫茫丶 + * @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 ( + + {imgs.map((src: string, i: number) => ( + + CardSwiper + + ))} + + ); +} diff --git a/src/app/features/swiper/components/CoverflowSwiper.tsx b/src/app/features/swiper/components/CoverflowSwiper.tsx new file mode 100644 index 0000000..7840ee6 --- /dev/null +++ b/src/app/features/swiper/components/CoverflowSwiper.tsx @@ -0,0 +1,45 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 15:31:30 + * @LastEditors: 白雾茫茫丶 + * @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 ( + + {imgs.map((src: string, i: number) => ( + + CoverflowSwiper + + ))} + + ); +} diff --git a/src/app/features/swiper/components/CreativeSwiper.tsx b/src/app/features/swiper/components/CreativeSwiper.tsx new file mode 100644 index 0000000..2761f50 --- /dev/null +++ b/src/app/features/swiper/components/CreativeSwiper.tsx @@ -0,0 +1,43 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 16:08:04 + * @LastEditors: 白雾茫茫丶 + * @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 ( + + {imgs.map((src: string, i) => ( + + CreativeSwiper + + ))} + + ); +} diff --git a/src/app/features/swiper/components/CubeSwiper.tsx b/src/app/features/swiper/components/CubeSwiper.tsx new file mode 100644 index 0000000..d67bd89 --- /dev/null +++ b/src/app/features/swiper/components/CubeSwiper.tsx @@ -0,0 +1,42 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 13:42:53 + * @LastEditors: 白雾茫茫丶 + * @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 ( + + {imgs.map((src: string, i: number) => ( + + CubeSwiper + + ))} + + ); +} diff --git a/src/app/features/swiper/components/FlipSwiper.tsx b/src/app/features/swiper/components/FlipSwiper.tsx new file mode 100644 index 0000000..7b3eb38 --- /dev/null +++ b/src/app/features/swiper/components/FlipSwiper.tsx @@ -0,0 +1,36 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 15:03:00 + * @LastEditors: 白雾茫茫丶 + * @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 ( + + {imgs.map((src: string, i: number) => ( + + FlipSwiper + + ))} + + ); +} diff --git a/src/app/features/swiper/components/ThumbnailSwiper.tsx b/src/app/features/swiper/components/ThumbnailSwiper.tsx new file mode 100644 index 0000000..07742ee --- /dev/null +++ b/src/app/features/swiper/components/ThumbnailSwiper.tsx @@ -0,0 +1,61 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 15:44:49 + * @LastEditors: 白雾茫茫丶 + * @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(); + + const onThumbsSwiper = (swiper: SwiperClass) => { + setThumbsSwiper(swiper); + }; + return ( +
+ + {imgs.map((src: string, i: number) => ( + + CubeSwiper + + ))} + + {/* 缩略图 */} + + {imgs.map((src: string, i: number) => ( + + CubeSwiper + + ))} + +
+ ); +} diff --git a/src/app/features/swiper/components/VisualSwiper.tsx b/src/app/features/swiper/components/VisualSwiper.tsx new file mode 100644 index 0000000..22471e9 --- /dev/null +++ b/src/app/features/swiper/components/VisualSwiper.tsx @@ -0,0 +1,72 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 17:09:09 + * @LastEditors: 白雾茫茫丶 + * @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 ( + + {imgs.map((src: string, i: number) => ( + + CubeSwiper + + ))} + + ); +} diff --git a/src/app/features/swiper/index.scss b/src/app/features/swiper/index.scss new file mode 100644 index 0000000..9829a6b --- /dev/null +++ b/src/app/features/swiper/index.scss @@ -0,0 +1,11 @@ +.thumbs-swiper { + .swiper-slide { + height: 100%; + opacity: 0.4; + transition: .3s all; + cursor: pointer; + } + .swiper-slide-thumb-active { + opacity: 1; + } +} \ No newline at end of file diff --git a/src/app/features/swiper/page.tsx b/src/app/features/swiper/page.tsx new file mode 100644 index 0000000..f09d080 --- /dev/null +++ b/src/app/features/swiper/page.tsx @@ -0,0 +1,165 @@ +/* + * @Author: 白雾茫茫丶 + * @Date: 2025-01-20 11:24:16 + * @LastEditors: 白雾茫茫丶 + * @LastEditTime: 2025-01-20 17:11:49 + * @Description: Swiper 幻灯片 + */ +'use client'; +import 'swiper/css'; +import './index.scss'; + +import { Card, CardBody, CardHeader, Divider } from '@heroui/react'; +import { useTranslations } from 'next-intl'; +import type { CreativeEffectOptions } from 'swiper/types'; + +import CardSwiper from './components/CardSwiper'; +import CoverflowSwiper from './components/CoverflowSwiper'; +import CreativeSwiper from './components/CreativeSwiper'; +import CubeSwiper from './components/CubeSwiper'; +import FlipSwiper from './components/FlipSwiper'; +import ThumbnailSwiper from './components/ThumbnailSwiper'; +import VisualSwiper from './components/VisualSwiper'; + +export default function Swiper() { + const t = useTranslations('Pages.swiper'); + + const creativeEffectOptions: CreativeEffectOptions[] = [ + { + prev: { + shadow: true, + translate: [0, 0, -400], + }, + next: { + translate: ['100%', 0, 0], + }, + }, + { + prev: { + shadow: true, + translate: ['-120%', 0, -500], + }, + next: { + shadow: true, + translate: ['120%', 0, -500], + }, + }, + { + prev: { + shadow: true, + translate: ['-20%', 0, -1], + }, + next: { + translate: ['100%', 0, 0], + }, + }, + { + prev: { + shadow: true, + translate: [0, 0, -800], + rotate: [180, 0, 0], + }, + next: { + shadow: true, + translate: [0, 0, -800], + rotate: [-180, 0, 0], + }, + }, + { + prev: { + shadow: true, + translate: ['-125%', 0, -800], + rotate: [0, 0, -90], + }, + next: { + shadow: true, + translate: ['125%', 0, -800], + rotate: [0, 0, 90], + }, + }, + { + prev: { + shadow: true, + origin: 'left center', + translate: ['-5%', 0, -200], + rotate: [0, 100, 0], + }, + next: { + origin: 'right center', + translate: ['5%', 0, -200], + rotate: [0, -100, 0], + }, + }, + ]; + return ( +
+ + +

{t('cube')}

+
+ + + + +
+ + +

{t('flip')}

+
+ + + + +
+ + +

{t('card')}

+
+ + + + +
+ + +

{t('coverflow')}

+
+ + + + +
+ + +

{t('thumbnail')}

+
+ + + + +
+ + +

{t('creative')}

+
+ + +
+ {creativeEffectOptions.map((option, i) => ( + + ))} +
+
+
+ + +

{t('visual')}

+
+ + + + +
+
+ ); +} diff --git a/src/middleware.ts b/src/middleware.ts index 6183e95..3df9438 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -2,7 +2,7 @@ * @Author: 白雾茫茫丶 * @Date: 2025-01-03 15:16:03 * @LastEditors: 白雾茫茫丶 - * @LastEditTime: 2025-01-16 14:29:05 + * @LastEditTime: 2025-01-20 10:33:05 * @Description: 全局中间件 */ @@ -29,9 +29,9 @@ export default auth(async (req: NextRequest) => { return NextResponse.json(responseMessage(null, '请先登录', -1)); } // 如果不是GET请求,返回一个带有消息的响应 - if (!isProtectedRoute) { - return NextResponse.json(responseMessage(null, '演示系统,禁止操作', -1)); - } + // if (!isProtectedRoute) { + // return NextResponse.json(responseMessage(null, '演示系统,禁止操作', -1)); + // } } // 检查是否为不受保护的路由