如何自定义yet-another-react-lightbox在缩略图下方添加投票组件?
实现方案:在yet-another-react-lightbox中添加固定投票组件
需求可行性确认
完全可以实现,你的思路部分正确,但不需要自定义幻灯片,通过以下两种方式即可实现投票组件固定显示在幻灯片下方/每张幻灯片可见的效果:
方案一:利用render prop快速插入固定投票组件
yet-another-react-lightbox提供了render prop,可直接在Lightbox容器内插入自定义元素,适合快速实现固定位置的投票组件。
修改你的代码如下:
import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails"; import "yet-another-react-lightbox/plugins/thumbnails.css"; import "yet-another-react-lightbox/plugins/captions.css"; import Captions from "yet-another-react-lightbox/plugins/captions"; import Lightbox from "yet-another-react-lightbox"; import { ItemDetail } from "@/types/photoNews"; const AlbumModal = ({ albumItem, // 修正参数名与解构定义一致 open, setOpen, }: { albumItem: ItemDetail; open: boolean; setOpen: (value: React.SetStateAction<boolean>) => void; }) => { // 基于albumItem生成幻灯片数据(补充你缺失的slides逻辑) const slides = albumItem.photos.map(photo => ({ src: photo.url, alt: photo.alt, id: photo.id // 用于投票时关联对应幻灯片 })); // 处理投票请求的函数 const handleVote = async (optionId: string) => { const res = await fetch("/api/vote", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ optionId, photoId: slides[0].id // 若需对应当前幻灯片,可结合carousel索引动态获取 }) }); const result = await res.json(); // 后续处理投票结果,比如更新状态或提示用户 }; return ( <Lightbox open={open} close={() => setOpen(false)} slides={slides} carousel={{ finite: true, imageFit: "contain", }} plugins={[Thumbnails, Captions]} captions={{ descriptionMaxLines: 1, descriptionTextAlign: "center" }} styles={{ container: { backgroundColor: "rgba(0, 0, 0, .95)", }, captionsDescriptionContainer: { paddingBottom: "12%", // 调整底部内边距,给投票组件预留空间 }, }} // 通过render.footer插入固定在底部的投票组件 render={{ footer: () => ( <div style={{ position: "fixed", bottom: "20px", left: "50%", transform: "translateX(-50%)", width: "80%", backgroundColor: "rgba(0,0,0,0.8)", padding: "16px", borderRadius: "8px", color: "#fff" }}> <h3 style={{ margin: "0 0 12px 0" }}>{albumItem.voteQuestion}</h3> <div style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}> {albumItem.voteOptions.map(option => ( <button key={option.id} onClick={() => handleVote(option.id)} style={{ padding: "8px 16px", borderRadius: "4px", border: "none", cursor: "pointer", backgroundColor: "#2196f3", color: "#fff" }} > {option.label} </button> ))} </div> </div> ) }} /> ); }; export default AlbumModal;
关键说明:
render.footer插入的组件会固定在Lightbox容器底部,不受幻灯片切换影响- 若需每张幻灯片对应不同投票,可通过
useLightboxhook获取当前carousel.index,动态匹配对应幻灯片的投票数据
方案二:自定义Lightbox插件(适合功能复用)
如果希望投票功能作为独立模块复用,可封装成自定义插件:
- 先创建投票插件组件:
// @/components/VotePlugin.tsx import { useLightbox } from "yet-another-react-lightbox"; interface VoteOption { id: string; label: string; } interface VotePluginProps { question: string; options: VoteOption[]; } const VotePlugin = ({ question, options }: VotePluginProps) => { const { carousel } = useLightbox(); const currentSlide = carousel.slides[carousel.index]; const handleVote = async (optionId: string) => { await fetch("/api/vote", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ optionId, photoId: currentSlide.id }) }); // 处理投票结果逻辑 }; return ( <div style={{ position: "fixed", bottom: "20px", left: "50%", transform: "translateX(-50%)", width: "80%", backgroundColor: "rgba(0,0,0,0.8)", padding: "16px", borderRadius: "8px", color: "#fff" }}> <h3 style={{ margin: "0 0 12px 0" }}>{question}</h3> <div style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}> {options.map(option => ( <button key={option.id} onClick={() => handleVote(option.id)} style={{ padding: "8px 16px", borderRadius: "4px", border: "none", cursor: "pointer", backgroundColor: "#2196f3", color: "#fff" }} > {option.label} </button> ))} </div> </div> ); }; // 包装成Lightbox插件格式 export const VotePluginWrapper = (props: VotePluginProps) => ({ render: () => <VotePlugin {...props} /> });
- 在AlbumModal中引入并使用插件:
import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails"; import "yet-another-react-lightbox/plugins/thumbnails.css"; import "yet-another-react-lightbox/plugins/captions.css"; import Captions from "yet-another-react-lightbox/plugins/captions"; import Lightbox from "yet-another-react-lightbox"; import { ItemDetail } from "@/types/photoNews"; import { VotePluginWrapper } from "@/components/VotePlugin"; const AlbumModal = ({ albumItem, open, setOpen, }: { albumItem: ItemDetail; open: boolean; setOpen: (value: React.SetStateAction<boolean>) => void; }) => { const slides = albumItem.photos.map(photo => ({ src: photo.url, alt: photo.alt, id: photo.id })); return ( <Lightbox open={open} close={() => setOpen(false)} slides={slides} carousel={{ finite: true, imageFit: "contain", }} // 将自定义插件加入plugins数组 plugins={[ Thumbnails, Captions, VotePluginWrapper({ question: albumItem.voteQuestion, options: albumItem.voteOptions }) ]} captions={{ descriptionMaxLines: 1, descriptionTextAlign: "center" }} styles={{ container: { backgroundColor: "rgba(0, 0, 0, .95)", }, captionsDescriptionContainer: { paddingBottom: "12%", }, }} /> ); }; export default AlbumModal;
关键说明:
- 自定义插件通过
useLightboxhook获取当前幻灯片状态,可轻松实现"每张幻灯片对应不同投票"的逻辑 - 插件化设计更适合复杂功能的复用和维护
内容的提问来源于stack exchange,提问作者Menna Magdy
相关产品推荐
相关产品推荐

