在 refine 项目中使用 Swiper.js:构建触摸滑动轮播与缩略图画廊的完整指南
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
Swiper.js 是一款轻量而强大的 JavaScript 触摸滑动库,可用于为网站与 Web 应用快速添加支持触摸手势、响应式布局的轮播(Slider)组件。本文将以当前 refine 仓库中 documentation/blog/2023-12-07-swiper-js.md 为骨架,结合仓库内 examples/win95/src/routes/rvc-website/home.tsx 的真实使用案例,系统讲解 Swiper 的安装、初始化、模块自定义、React 集成以及 Web Component 用法,帮助你掌握从零搭建可定制轮播的完整技术方案。
Swiper.js 是什么:为什么轮播场景值得选择它
滑块(Slider)已经成为网站与 Web 应用不可或缺的组成部分,它能够快速抓住用户的注意力,并突出展示重要的信息、商品或特性。市面上有大量用于制作滑块的库,而Swiper是其中值得关注的一个。
Swiper.js是一个强大的 JavaScript 库,可以让你快速为网站或 Web 应用添加支持触摸和响应式布局的滑块。它之所以被广泛采用,主要得益于两点:
- 定制灵活度高:支持模块化架构,按需加载 Navigation(导航)、Pagination(分页)、Scrollbar(滚动条)、Thumbs(缩略图)等能力;
- 框架支持广泛:除原生 JavaScript 外,还提供了 React、Vue、Angular 等主流框架的官方绑定。
在 refine 仓库中,Swiper 也确实被真实用于构建前端展示场景:win95 示例项目的首页使用swiper/react渲染"最新上映影片"横滑列表(详见下文"仓库实战"小节),这为本文的实践部分提供了可直接对照的仓库级范例。
在项目中引入 Swiper.js 的三种方式
1. 下载 Swiper 资源
如果你希望完全离线使用,可以下载 Swiper 的本地资源包(完整压缩包可通过其发布渠道获取),然后将 CSS 与 JS 文件放入项目静态目录手动引入。
2. 通过 CDN 引入
只需在 HTML 文件中添加以下代码,即可通过 CDN 快速引入 Swiper 的样式与脚本:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" /> <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>如果你在浏览器中直接使用 ES Modules,也有对应的 CDN 版本:
<script type="module"> import Swiper from 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.mjs' const swiper = new Swiper(...) </script>注意上面的版本号为@11,这与当前仓库中锁定安装的 Swiper 大版本一致(详见下文"版本事实")。
3. 通过 npm 安装
对于 React 等模块化项目,推荐使用 npm(或 pnpm/yarn)安装:
npm install swiper然后在你自己的 JavaScript / TypeScript 文件中导入:
// import Swiper JS import Swiper from 'swiper'; // import Swiper styles import 'swiper/swiper-bundle.min.css'; const swiper = new Swiper(...);核心与模块的区别:Swiper 默认只导出基础版本,不包含任何附加模块(如Navigation、Pagination等)。因此,你需要从swiper/modules中额外导入并配置这些模块:
// core version + navigation, pagination modules: import Swiper from 'swiper'; import { Navigation, Pagination } from 'swiper/modules'; // import Swiper and modules styles import 'swiper/swiper.min.css'; import 'swiper/modules/navigation.min.css'; import 'swiper/modules/pagination.min.css'; // init Swiper: const swiper = new Swiper('.swiper', { // configure Swiper to use modules modules: [Navigation, Pagination], ... });如果你希望一次性导入包含全部模块的完整包(bundle),可以从swiper/bundle导入:
// import Swiper bundle with all modules installed import Swiper from 'swiper/bundle'; // import styles bundle import 'swiper/swiper-bundle.min.css'; // init Swiper: const swiper = new Swiper(...);定义 Swiper 的 HTML 结构
安装完成后,需要为 Swiper 搭建标准的 HTML 布局。Swiper 对标记结构有明确约定:外层为容器.swiper,内部必须包含.swiper-wrapper与若干.swiper-slide,其余(分页、导航、滚动条)均为可选挂载点:
<!-- Slider main container --> <div class="swiper"> <!-- Additional required wrapper --> <div class="swiper-wrapper"> <!-- Slides --> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> ... </div> <!-- If we need pagination --> <div class="swiper-pagination"></div> <!-- If we need navigation buttons --> <div class="swiper-button-prev"></div> <div class="swiper-button-next"></div> <!-- If we need scrollbar --> <div class="swiper-scrollbar"></div> </div>初始化 Swiper:两个核心参数
在 HTML 就绪后,通过new Swiper(...)完成初始化:
const swiper = new Swiper(".swiper", { // Optional parameters direction: "vertical", loop: true, // If we need pagination pagination: { el: ".swiper-pagination", }, // Navigation arrows navigation: { nextEl: ".swiper-button-next", prevEl: ".swiper-button-prev", }, // And if we need scrollbar scrollbar: { el: ".swiper-scrollbar", }, });Swiper构造函数接受两个参数:
- 目标元素:以
CSS选择器形式指向 Swiper 的容器元素(上例中的.swiper); - 配置对象:用于传入
navigation、pagination、modules、scrollbar、direction、loop等大量可选配置项。
Swiper 的配置参数非常丰富,官方 API 文档中列出了完整的参数清单;在本文后续小节,我们会结合仓库源码逐一剖析最常用的模块参数。
Swiper 的常用方法与属性
初始化之后,就可以通过 Swiper 实例访问一系列实用的属性:
swiper.activeIndex:当前滑块的索引值,可赋值为数字;swiper.previousIndex:上一个滑块的索引值,可赋值为数字;swiper.allowSlideNext:禁用或启用切换到下一张滑块的能力;swiper.allowSlidePrev:禁用或启用切换到上一张滑块的能力;swiper.el:滑块容器对应的 HTML 元素;swiper.width:滑块容器的宽度;swiper.height:滑块容器的高度;swiper.swipeDirection:指定滑动方向,取值为'prev'或'next'。
以及常用的方法:
swiper.changeDirection(direction, needUpdate)swiper.slidePrev(speed, runCallbacks)swiper.slideTo(index, speed, runCallbacks)
在仓库的 win95 示例中,正是通过
controlledSwiper?.slidePrev()与controlledSwiper?.slideNext()驱动自定义箭头按钮切换轮播,与本文介绍的方法用法完全一致。
监听 Swiper 事件
Swiper 内置了许多有用的事件,可以通过两种方式绑定:
方式一:初始化时通过on参数注册
const swiper = new Swiper(".swiper", { // ... on: { init: function () { console.log("swiper initialized"); }, }, });方式二:初始化后通过实例的on方法注册
const swiper = new Swiper(".swiper", { // ... }); swiper.on("slideChange", function () { console.log("slide changed"); });常用事件包括:
activeIndexChange:当滑块的当前索引发生变化时触发;slideChange:当滑块的活动索引发生变化时触发;click:当 Swiper 容器被点击时触发。
在 React 集成中,这些事件会以on{事件名}的 props 形式暴露(见下文"React 中的 Swiper props")。
Swiper 的样式体系
Swiper 提供多套 CSS 样式集,按需选择即可:
swiper/swiper-bundle.min.css:Swiper 核心样式与所有模块样式的合并压缩版;swiper/swiper.min.css:仅 Swiper 核心样式(不含模块样式);swiper/modules/{{moduleName}}.min.css:按小写模块名(如 Navigation、Pagination)对应的压缩模块样式;swiper/modules/{{moduleName}}.css:同上,但为未压缩版本。
Swiper 也支持单独导入模块样式——例如只导入导航模块的压缩样式:
import 'swiper/modules/navigation.min.css';注意:如果已经导入了 bundle 样式,则模块样式是可选的,无需重复导入。此外 Swiper 官方还提供 SCSS、Less 等其他样式方案。
深入自定义 Swiper 模块
Swiper 的模块可以通过参数进行多样化定制,下面逐一讲解。
Navigation 导航
Navigation 模块提供两个核心参数:
- prevEl:字符串类型,值为 CSS 选择器或 HTML 元素,指向点击后切换"上一张"的按钮;
- nextEl:字符串类型,值为 CSS 选择器或 HTML 元素,指向点击后切换"下一张"的按钮。
以下示例将 HTML 模板中的.swiper-button-prev、.swiper-button-next元素分别绑定到navigation.prevEl与navigation.nextEl:
JavaScript 代码:
import Swiper from 'swiper'; import { Navigation } from 'swiper/modules'; // import Swiper and modules styles import 'swiper/swiper.min.css'; import 'swiper/modules/navigation.min.css'; const swiper = new Swiper('.swiper', { modules: [Navigation], ...., // Navigation arrows navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, }); // OR (Alternative) const swiper = new Swiper('.swiper', { modules: [Navigation], ...., }); swiper.nextEl = '.swiper-button-next'; swiper.prevEl = '.swiper-button-prev';HTML 模板:
<!-- Slider main container --> <div class="swiper"> <!-- Additional required wrapper --> <div class="swiper-wrapper"> <!-- Slides --> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> ... </div> <!-- navigation buttons --> <div class="swiper-button-prev"></div> <div class="swiper-button-next"></div> </div>Pagination 分页
Pagination 模块提供以下参数:
- bullets:数组类型,存放所有分页小圆点的 HTML 元素,例如通过
swiper.pagination.bullets[1]获取指定滑块的圆点元素; - el:分页容器元素的 HTMLElement。
以下示例将.swiper-pagination绑定到pagination.el,并开启clickable(点击圆点跳转对应滑块):
JavaScript 代码:
import Swiper from 'swiper'; import { Pagination, Navigation } from 'swiper/modules'; // import Swiper and modules styles import 'swiper/swiper.min.css'; import 'swiper/modules/navigation.min.css'; import 'swiper/modules/pagination.min.css'; const swiper = new Swiper('.swiper', { modules: [Pagination, Navigation], // If we need pagination pagination: { el: '.swiper-pagination', clickable: true }, ... }); // OR (Alternative) const swiper = new Swiper('.swiper', { modules: [Pagination, Navigation], ..., }); swiper.el = '.swiper-pagination';HTML 模板:
<!-- Slider main container --> <div class="swiper"> <!-- Additional required wrapper --> <div class="swiper-wrapper"> <!-- Slides --> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> ... </div> <!-- If we need pagination --> <div class="swiper-pagination"></div> </div>Scrollbar 滚动条
Scrollbar 模块提供以下参数:
- dragEl:滚动条中可拖拽手柄元素的 HTMLElement;
- el:滚动条容器元素的 HTMLElement。
以下示例将.swiper-scrollbar绑定到scrollbar.el:
JavaScript 代码:
import Swiper from 'swiper'; import { Scrollbar } from 'swiper/modules'; // import Swiper and modules styles import 'swiper/swiper.min.css'; import 'swiper/modules/scrollbar.min.css'; const swiper = new Swiper('.swiper', { modules: [Scrollbar], // And if we need scrollbar scrollbar: { el: '.swiper-scrollbar', }, }); // OR (Alternative) const swiper = new Swiper('.swiper', { modules: [Scrollbar], ...., }); swiper.el = '.swiper-scrollbar';HTML 模板:
<!-- Slider main container --> <div class="swiper"> <!-- Additional required wrapper --> <div class="swiper-wrapper"> <!-- Slides --> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> ... </div> <!-- If we need scrollbar --> <div class="swiper-scrollbar"></div> </div>Thumbs 缩略图
实现缩略图画廊需要两个 Swiper 实例协同工作:
- 第一个 Swiper 实例:主滑块,由缩略图控制其切换;
- 第二个 Swiper 实例:缩略图滑块本身。
Thumbs 模块的核心参数:
- swiper:接收缩略图 Swiper 的实例。
以下示例通过swiper2(主滑块)的thumbs.swiper属性引用swiper(缩略图滑块)实例:
JavaScript 代码:
import Swiper from "swiper"; import { Thumbs } from "swiper/modules"; // import Swiper and modules styles import "swiper/swiper.min.css"; import "swiper/modules/thumbs.min.css"; // Initialize Swiper let swiper = new Swiper(".mySwiper", { spaceBetween: 10, slidesPerView: 4, freeMode: true, watchSlidesProgress: true, }); let swiper2 = new Swiper(".mySwiper2", { modules: [Thumbs], spaceBetween: 10, thumbs: { swiper: swiper, }, });这里缩略图滑块开启freeMode与watchSlidesProgress,前者让缩略图可以自由滑动、后者确保缩略图的进度(高亮)能随主滑块实时同步——这是画廊类轮播的常见组合。
HTML 模板:
<div class="swiper-container"> <div class="swiper mySwiper2"> <div class="swiper-wrapper"> <div class="swiper-slide slide_1">Slide 1</div> <div class="swiper-slide slide_2">Slide 2</div> <div class="swiper-slide slide_3">Slide 3</div> <div class="swiper-slide slide_4">Slide 4</div> <div class="swiper-slide slide_5">Slide 5</div> </div> <div class="swiper-button-next"></div> <div class="swiper-button-prev"></div> </div> <div thumbsSlider="" class="swiper mySwiper"> <div class="swiper-wrapper"> <div class="swiper-slide slide_1">Slide 1</div> <div class="swiper-slide slide_2">Slide 2</div> <div class="swiper-slide slide_3">Slide 3</div> <div class="swiper-slide slide_4">Slide 4</div> <div class="swiper-slide slide_5">Slide 5</div> </div> </div> </div>在 React 中使用 Swiper
Swiper 支持 React、Vue、Angular 等主流框架,本节聚焦 React 集成方式。
安装与组件导入
Swiper React 属于主 Swiper 库的一部分,仅通过 NPM 访问:
npm i swiper安装完成后,从swiper/react导出即可使用 React 组件。
基础用法:Swiper与SwiperSlide
swiper/react导出两个核心组件:
<Swiper></Swiper>:代表 Swiper 容器元素;<SwiperSlide></SwiperSlide>:代表单个滑块。
// Import Swiper React components import { Swiper, SwiperSlide } from "swiper/react"; // Import Swiper styles import "swiper/css"; export default () => { return ( <Swiper> <SwiperSlide>Content 1</SwiperSlide> <SwiperSlide>Content 2</SwiperSlide> <SwiperSlide>Content 3</SwiperSlide> <SwiperSlide>Content 4</SwiperSlide> </Swiper> ); };注意:Swiper React 默认使用 Swiper 核心版(不含附加模块)。如果要使用Navigation、Pagination等模块,必须先通过modules引入:
// import Swiper core and required modules import { Navigation, Pagination, Scrollbar, A11y } from "swiper/modules"; import { Swiper, SwiperSlide } from "swiper/react"; // Import Swiper styles import "swiper/css"; import "swiper/css/navigation"; import "swiper/css/pagination"; import "swiper/css/scrollbar"; export default () => { return ( <Swiper // install Swiper modules modules={[Navigation, Pagination, Scrollbar, A11y]} navigation={true} pagination={true} > <SwiperSlide>Content 1</SwiperSlide> <SwiperSlide>Content 2</SwiperSlide> <SwiperSlide>Content 3</SwiperSlide> <SwiperSlide>Content 4</SwiperSlide> ... </Swiper> ); };其中A11y是无障碍模块(增强键盘与读屏器支持),搭配navigation={true}、pagination={true}即可一键开启上一张/下一张按钮与分页圆点。
Swiper props
所有 Swiper 参数都会作为组件props传给<Swiper>,此外还附加了以下属性:
tag:Swiper 容器的 HTML 元素标签;wrapperTag:Swiper wrapper 的 HTML 元素标签;onSwiper:接收 Swiper 实例的回调。
同时,所有 Swiper 事件都以on{事件名}形式暴露为 props,例如SlideChange事件对应onSlideChange:
... <Swiper onSlideChange={() => {/*...*/}} ... >在仓库的 win95 示例中,onSwiper={(swiper) => setControlledSwiper(swiper)}正是利用该回调把 Swiper 实例存入 React state,供外部箭头按钮通过slidePrev()/slideNext()调用——这是"外部控件 + Swiper"的经典写法。
SwiperSlide props 与渲染函数
<SwiperSlide></SwiperSlide>组件支持以下额外属性:
tag:滑块 HTML 元素标签;zoom:是否启用 zoom 模式所需的额外包装层;virtualIndex:滑块的"真实"索引,虚拟滑块场景下必须配置。
<SwiperSlide></SwiperSlide>还支持传入渲染函数,函数返回一个包含以下属性的对象:
isActive:当前滑块处于激活状态时为true;isPrev:当前滑块是激活滑块的前一张时为true;isNext:当前滑块是激活滑块的后一张时为true;isVisible:当前滑块可见时为true(需启用watchSlidesProgress);isDuplicate:当前滑块是重复项时为true(启用 loop 模式时出现)。
渲染函数示例:
<Swiper> <SwiperSlide> {({ isActive }) => ( <div>Current slide is {isActive ? "active" : "Slide 1"}</div> )} </SwiperSlide> </Swiper>Swiper Hooks:useSwiper与useSwiperSlide
Swiper hooks 是 React 下便捷获取 Swiper 实例与滑块数据的钩子。
useSwiper:在 Swiper 内部组件中直接获取Swiper实例:
// some-inner-component.jsx import { React } from "react"; import { useSwiper } from "swiper/react"; export default function SlideNextButton() { const swiper = useSwiper(); return ( <button onClick={() => swiper.slideNext()}>Slide to the next slide</button> ); }useSwiperSlide:供滑块内部的组件获取当前滑块数据(与<SwiperSlide>渲染函数暴露的数据一致):
// some-inner-component.jsx import { React } from "react"; import { useSwiperSlide } from "swiper/react"; export default function SlideTitle() { const swiperSlide = useSwiperSlide(); return ( <p>Current slide is {swiperSlide.isActive ? "active" : "not active"}</p> ); }在 React 中使用 Swiper Web Component(Elements)
Swiper 还提供了 Web Component 形态(swiper-container/swiper-slide)。由于 React 目前对自定义元素(Web Components)没有原生支持,在 React 中使用 Swiper Element 时需要:
- 以
props形式传入参数; - 使用自定义初始化(
register()注册组件); - 事件无法使用 React 的
on[事件]语法,必须通过.addEventListener或在初始化参数中传入on回调:
import { useEffect, useRef } from "react"; import { register } from "swiper/element/bundle"; register(); export default function App() { const swiperElRef = useRef(null); useEffect(() => { // listen for Swiper events using addEventListener swiperElRef.current.addEventListener("swiperprogress", (e) => { const [swiper, progress] = e.detail; console.log(progress); }); swiperElRef.current.addEventListener("swiperslidechange", (e) => { console.log("slide changed"); }); }, []); return ( <swiper-container ref={swiperElRef} slides-per-view="3" navigation="true" pagination="true" > <swiper-slide>Slide 1</swiper-slide> <swiper-slide>Slide 2</swiper-slide> <swiper-slide>Slide 3</swiper-slide> ... </swiper-container> ); }注意事件名带swiper前缀(如swiperprogress、swiperslidechange),事件数据通过e.detail解构获取(如const [swiper, progress] = e.detail),这是 Web Component 与 React 组件 API 的最大差异点。
仓库实战:win95 示例中的 Swiper 应用
为了让上面的 API 落到真实代码,我们剖析 refine 仓库中的 win95 示例。其依赖声明在 examples/win95/package.json:
"swiper": "^11.1.0"而 pnpm-lock.yaml 中锁定安装的版本为swiper@11.1.1——这也印证了前文 CDN 示例中@11大版本号的有效性。
在 examples/win95/src/routes/rvc-website/home.tsx 中,可以看到一套完整的"外部控件驱动轮播"实现:
导入(第 6-9 行):
import { Controller } from "swiper/modules"; import { Swiper, SwiperSlide } from "swiper/react"; import type { Swiper as ISwiper } from "swiper/types"; import "swiper/css";这里同时体现了本文多个要点:从swiper/modules按需导入Controller模块、从swiper/react导入组件、用swiper/types标注实例类型、从swiper/css导入核心样式。
轮播主体(第 109-114 行):
<Swiper modules={[Controller]} controller={{ control: controlledSwiper }} onSwiper={(swiper) => setControlledSwiper(swiper)} slidesPerView={5} loop={!!titles?.length} >onSwiper回调把实例存入 state(对应上文"onSwiperprops");controller.control让该轮播可被外部controlledSwiper实例控制;slidesPerView={5}一次展示 5 张海报;loop根据数据是否为空动态开启循环模式。
外部按钮(第 107、139 行):
onClick={() => controlledSwiper?.slidePrev()} onClick={() => controlledSwiper?.slideNext()}这两个箭头按钮通过slidePrev()/slideNext()驱动轮播,正是"Swiper 方法与属性"一节所讲实例方法的实战运用。
样式定制(第 337-341 行):
.swiper-slide { display: flex; align-items: center; justify-content: center; }通过 styled-components 覆盖.swiper-slide布局,体现了"Swiper 样式体系"中核心样式与业务样式分层定制的思路。整体数据由 refine 的useListhook 提供(resource: "titles",按created_at倒序,每页 10 条),即"refine 数据层 + Swiper 展示层"的典型组合。
结语
本文围绕Swiper.js这一功能丰富、易于使用的轮播库,覆盖了从安装(下载 / CDN / npm)、HTML 标记、初始化参数,到方法属性、事件监听、样式体系,再到 Navigation、Pagination、Scrollbar、Thumbs 四大模块的自定义,以及 React 组件、props、渲染函数、hooks 与 Web Component 的完整用法,并通过 refine 仓库中的 win95 示例验证了这些 API 在生产级代码中的真实形态。
Swiper.js 是一个特性非常丰富的库,建议在实际项目中结合其官方 API 文档持续探索更多参数与模块组合;而本文讲解的模块化导入、事件绑定、外部控件驱动等模式,已经足够支撑你在 refine 这类 React 项目中构建出体验良好的触摸轮播、画廊与横向内容列表。
参考与延伸阅读(仓库内路径):
- 本文主题文档:documentation/blog/2023-12-07-swiper-js.md
- 实战代码:examples/win95/src/routes/rvc-website/home.tsx
- 依赖声明:examples/win95/package.json
- 锁定版本:pnpm-lock.yaml
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考