You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自定义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容器底部,不受幻灯片切换影响
  • 若需每张幻灯片对应不同投票,可通过useLightbox hook获取当前carousel.index,动态匹配对应幻灯片的投票数据

方案二:自定义Lightbox插件(适合功能复用)

如果希望投票功能作为独立模块复用,可封装成自定义插件:

  1. 先创建投票插件组件:
// @/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} />
});
  1. 在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;

关键说明:

  • 自定义插件通过useLightbox hook获取当前幻灯片状态,可轻松实现"每张幻灯片对应不同投票"的逻辑
  • 插件化设计更适合复杂功能的复用和维护

内容的提问来源于stack exchange,提问作者Menna Magdy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 07:39:56