欢迎扫码,加作者微信

danmu弹幕

2025-08-27 04:29:56
2025-08-27 04:30:08

官方文档

https://imtaotao.github.io/danmu/document/en/

官方示例

https://imtaotao.github.io/danmu/

language 复制代码
import { create } from 'danmu';
import { useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom/client';
import { getArgFromUrl, _T, useIsEn } from '@dana/components';
import { getBullet } from 'api';

const BulletItem = ({
  data,
}: {
  data: {
    avatar1: string;
    avatar2: string;
    gift: string;
  };
}) => {
  const isEn = useIsEn();

  const bulletMap: Record<number, string> = {
    1: _T('我对你的爱是永恒的。'),
    2: _T('我想和你分享每一刻。'),
    3: _T('你是我心中的珍宝。'),
    4: _T('我的爱像海一样深。'),
    5: _T('爱你是我生命的目的。'),
    6: _T('你是我无法忘记的梦想。'),
    7: _T('我们可以一起面对一切。'),
    8: _T('你的笑容照亮了我的生活。'),
    9: _T('我想永远和你一起旅行。'),
  };

  const bullet = bulletMap[Math.floor(Math.random() * 9) + 1];

  return (
    <div className="flex justify-between items-center">
      <div className="flex relative z-10 justify-center items-center">
        <div className="relative w-[52px] h-[52px] flex justify-center items-center">
          <div
            className="w-[40px] h-[40px] bg-contain bg-center rounded-full"
            style={{
              backgroundImage: `url(${data.avatar1})`,
            }}
          ></div>
          <div className="bg-love-head w-[52px] h-[52px] bg-cover absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%]"></div>
        </div>
        <div className="mx-[-10px] w-[38px] h-[39px] flex justify-center items-center relative z-10">
          <div className="bg-mask w-[38px] h-[38px] bg-cover  absolute top-0 left-0"></div>
          <div
            className="w-[30px] h-[30px] bg-cover"
            style={{
              backgroundImage: `url(${data.gift})`,
            }}
          ></div>
        </div>
        <div className="relative w-[52px] h-[52px] flex justify-center items-center">
          <div
            className="w-[40px] h-[40px] bg-contain bg-center rounded-full"
            style={{
              backgroundImage: `url(${data.avatar2})`,
            }}
          ></div>
          <div className="bg-love-head w-[52px] h-[52px] bg-cover absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%]"></div>
        </div>
      </div>
      <div
        className={`flex  items-center w-[276px] h-[38px] bg-bullet-item bg-cover pl-[35px] ${isEn ? 'justify-start ml-[-30px]' : 'justify-end scale-x-[-1] mr-[-30px]'}`}
        dir=""
      >
        <div
          className={`text-[#FDFF83]
                text-[13px] font-bold [text-shadow:0px_2px_2px_rgba(0,0,0,0.60)] ${isEn ? 'text-right' : 'text-left scale-x-[-1]'} text-nowrap`}
        >
          {bullet}
        </div>
      </div>
    </div>
  );
};

const Bullet = () => {
  const screenRef = useRef<any>();
  const isEn = useIsEn();
  const [bulletData, setBulletData] = useState<any[]>([]);

  const fetchData = async () => {
    const res = await getBullet();
    let bulletData = res;

    setBulletData(bulletData);

    bulletData.forEach((item, index) => {
      screenRef.current.push(
        {
          avatar1: item.sendAvatar,
          avatar2: item.receiveAvatar,
          gift: item.giftSpic,
        },
        {
          plugin: {
            destroyed(danmaku: any) {
              danmaku.loops = 0; //
              screenRef.current.push(danmaku);
            },
          },
        },
      );
    });
  };

  const checkElementAndInit = () => {
    const container = document.getElementById('bullet');
    if (container) {
      // 元素存在,初始化弹幕
      screenRef.current = create({
        rate: 0.5,
        trackHeight: 52,
        mode: 'strict',
        direction: isEn ? 'right' : 'left',
        limits: {
          stash: Infinity,
          view: 20,
        },
        plugin: {
          $beforeMove(danmaku) {
            // 设置循环
            // danmaku.setloop();
          },
          $createNode(danmaku) {
            if (danmaku.node) {
              ReactDOM.createRoot(danmaku.node).render(
                <BulletItem
                  data={{
                    avatar1: (danmaku.data as any).avatar1,
                    avatar2: (danmaku.data as any).avatar2,
                    gift: (danmaku.data as any).gift,
                  }}
                />,
              );
            }
          },
        },
      });

      // 挂载并开始渲染
      screenRef.current.mount(container);
      screenRef.current.startPlaying();
      fetchData();
    } else {
      // 元素不存在,继续轮询
      setTimeout(checkElementAndInit, 100); // 每100ms检查一次
    }
  };

  useEffect(() => {
    // 给页面中某个元素初始化弹幕屏幕,一般为一个大区块。此处的配置项全局生效
    screenRef.current = create({
      rate: 0.5,
      trackHeight: 52,
      direction: isEn ? 'right' : 'left',
      mode: 'strict',
      // durationRange: [5000, 5000],
      limits: {
        stash: Infinity,
        view: 20,
      },
      plugin: {
        $beforeMove(danmaku) {
          // 设置循环
          // danmaku.setloop();
        },
        $createNode(danmaku) {
          if (danmaku.node) {
            ReactDOM.createRoot(danmaku.node).render(
              <BulletItem
                data={{
                  avatar1: (danmaku.data as any).avatar1,
                  avatar2: (danmaku.data as any).avatar2,
                  gift: (danmaku.data as any).gift,
                }}
              />,
            );
          }
        },
      },
    });

    // -----------------------------
    setTimeout(checkElementAndInit);
  }, []);

  return (
    <div>
      <div className="relative pt-[28px] w-[375px] h-[507px] bg-cover bg-bullet-bg">
        <div className="text-primary">{_T('CP世界')}</div>
        <div className="w-[265px] h-[48px] bg-cover bg-bullet-title flex justify-center items-center mx-auto mt-[20px]">
          <div className="text-[#fff] text-[12px] font-normal text-center px-[10px] leading-tight">
            {_T('发送单个CP礼物>=5000金币到你的CP将显示')}
          </div>
        </div>
        <div className="mx-auto w-[350px] h-[320px] pt-[20px]">
          <div id="bullet" className="w-[350px] h-[320px]"></div>
        </div>
      </div>
    </div>
  );
};

export default Bullet;
文章目录

生成中...

扫码赞赏

感谢您的支持与鼓励

安全支付

支付赞赏

您的支持是我们前进的动力

留言
快捷金额
自定义金额
¥

安全保障

采用银行级加密技术,保障您的支付安全

暂无评论,欢迎留下你的评论

暂无评论

期待您的精彩留言!
成为第一个评论的人吧 ✨

写下第一条评论
Copyright © 2025 粤ICP备19043740号-1
🎉 今日第 1 位访客 📊 年访问量 0 💝 累计赞赏 1000+