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

如何将public文件夹内的bg.html作为组件引入React的HeroHome.jsx

将bg.html动画作为背景引入React组件的实现方案

步骤1:迁移并适配资源

  1. 把bg.html关联的style.css、script.js复制到React项目的src/assets目录下,将style.css重命名为bg-animation.css以便区分。
  2. 替换CDN依赖,用npm安装所需库:
npm install gsap lodash

步骤2:创建BgAnimation React组件

新建src/components/BgAnimation.jsx,将原bg.html的动画逻辑转换为React组件:

import React, { useEffect, useRef } from 'react';
import gsap from 'gsap';
import _ from 'lodash';
import '../assets/bg-animation.css';

function BgAnimation() {
  const containerRef = useRef(null);

  useEffect(() => {
    // 复制原script.js中的动画逻辑,适配React环境
    const canvas = document.createElement('canvas');
    containerRef.current.appendChild(canvas);
    
    // 这里粘贴原script.js的核心动画代码,注意将DOM选择器替换为ref相关操作
    // 示例(对应原"Jump to Hyperspace"逻辑):
    const ctx = canvas.getContext('2d');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    // 原动画的初始化、帧循环等代码放到这里

    // 窗口 resize 适配
    const handleResize = _.debounce(() => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
    }, 100);
    window.addEventListener('resize', handleResize);

    // 清理函数
    return () => {
      gsap.killTweensOf('*');
      window.removeEventListener('resize', handleResize);
      if (canvas) containerRef.current.removeChild(canvas);
    };
  }, []);

  return <div ref={containerRef} className="bg-animation-container"></div>;
}

export default BgAnimation;

在bg-animation.css中添加容器样式:

.bg-animation-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

步骤3:在HeroHome.jsx中引入并使用背景组件

修改HeroHome.jsx,将BgAnimation作为底层背景插入:

import React, { useState } from 'react';
import Modal from '../utils/Modal';
import HeroImage from '../images/hero-image.png';
import BgAnimation from './BgAnimation';

function HeroHome() {
  const [videoModalOpen, setVideoModalOpen] = useState(false);

  return (
    <section className="relative min-h-screen">
      {/* 背景动画层 - 置于最底层,不干扰内容交互 */}
      <div className="absolute inset-0 pointer-events-none">
        <BgAnimation />
      </div>

      {/* 原有的Illustration元素(按需保留/移除) */}
      <div className="absolute left-1/2 transform -translate-x-1/2 bottom-0 pointer-events-none" aria-hidden="true">
        <svg width="1360" height="578" viewBox="0 0 1360 578" xmlns="http://www.w3.org/2000/svg">
          <defs>
            <linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="illustration-01">
              <stop stopColor="#FFF" offset="0%" />
              <stop stopColor="#EAEAEA" offset="77.402%" />
              <stop stopColor="#DFDFDF" offset="100%" />
            </linearGradient>
          </defs>
          <g fill="url(#illustration-01)" fillRule="evenodd">
            <circle cx="1232" cy="128" r="128" />
            <circle cx="155" cy="443" r="64" />
          </g>
        </svg>
      </div>

      {/* 内容容器 - 提升层级确保在背景之上 */}
      <div className="max-w-6xl mx-auto px-4 sm:px-6 relative z-10">
        <div className="pt-32 pb-12 md:pt-40 md:pb-20">
          <div className="text-center pb-12 md:pb-16">
            <h1 className="text-5xl md:text-6xl font-extrabold leading-tighter tracking-tighter mb-4" data-aos="zoom-y-out">Make your website <span className="bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-teal-400">wonderful</span></h1>
            <div className="max-w-3xl mx-auto">
              <p className="text-xl text-gray-600 mb-8" data-aos="zoom-y-out" data-aos-delay="150">Our landing page template works on all devices, so you only have to set it up once, and get beautiful results forever.</p>
              <div className="max-w-xs mx-auto sm:max-w-none sm:flex sm:justify-center" data-aos="zoom-y-out" data-aos-delay="300">
                <div>
                  <a className="btn text-white bg-blue-600 hover:bg-blue-700 w-full mb-4 sm:w-auto sm:mb-0" href="#0">Start free trial</a>
                </div>
                <div>
                  <a className="btn text-white bg-gray-900 hover:bg-gray-800 w-full sm:w-auto sm:ml-4" href="#0">Learn more</a>
                </div>
              </div>
            </div>
          </div>

          <div>
            <div className="relative flex justify-center mb-8" data-aos="zoom-y-out" data-aos-delay="450">
              <div className="flex flex-col justify-center">
                <img className="mx-auto" src={HeroImage} width="768" height="432" alt="Hero" />
                <svg className="absolute inset-0 max-w-full mx-auto md:max-w-none h-auto" width="768" height="432" viewBox="0 0 768 432" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
                  <defs>
                    <linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="hero-ill-a">
                      <stop stopColor="#FFF" offset="0%" />
                      <stop stopColor="#EAEAEA" offset="77.402%" />
                      <stop stopColor="#DFDFDF" offset="100%" />
                    </linearGradient>
                    <linearGradient x1="50%" y1="0%" x2="50%" y2="99.24%" id="hero-ill-b">
                      <stop stopColor="#FFF" offset="0%" />
                      <stop stopColor="#EAEAEA" offset="48.57%" />
                      <stop stopColor="#DFDFDF" stopOpacity="0" offset="100%" />
                    </linearGradient>
                    <radialGradient cx="21.152%" cy="86.063%" fx="21.152%" fy="86.063%" r="79.941%" id="hero-ill-e">
                      <stop stopColor="#4FD1C5" offset="0%" />
                      <stop stopColor="#81E6D9" offset="25.871%" />
                      <stop stopColor="#338CF5" offset="100%" />
                    </radialGradient>
                    <circle id="hero-ill-d" cx="384" cy="216" r="64" />
                  </defs>
                  <g fill="none" fillRule="evenodd">
                    <circle fillOpacity=".04" fill="url(#hero-ill-a)" cx="384" cy="216" r="128" />
                    <circle fillOpacity=".16" fill="url(#hero-ill-b)" cx="384" cy="216" r="96" />
                    <g fillRule="nonzero">
                      <use fill="#000" xlinkHref="#hero-ill-d" />
                      <use fill="url(#hero-ill-e)" xlinkHref="#hero-ill-d" />
                    </g>
                  </g>
                </svg>
              </div>
              <button className="absolute top-full flex items-center transform -translate-y-1/2 bg-white rounded-full font-medium group p-4 shadow-lg" onClick={(e) => { e.preventDefault(); e.stopPropagation(); setVideoModalOpen(true); }} aria-controls="modal">
                <svg className="w-6 h-6 fill-current text-gray-400 group-hover:text-blue-600 flex-shrink-0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                  <path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm0 2C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12z" />
                  <path d="M10 17l6-5-6-5z" />
                </svg>
                <span className="ml-3">Watch the full video (2 min)</span>
              </button>
            </div>

            <Modal id="modal" ariaLabel="modal-headline" show={videoModalOpen} handleClose={() => setVideoModalOpen(false)}>
              <div className="relative pb-9/16">
                <iframe className="absolute w-full h-full" src="https://player.vimeo.com/video/174002812" title="Video" allowFullScreen></iframe>
              </div>
            </Modal>

          </div>

        </div>

      </div>
    </section>
  );
}

export default HeroHome;

关键注意事项

  • 原script.js中的DOM操作必须替换为React ref调用,避免直接操作document导致的虚拟DOM冲突。
  • 动画的事件监听(如鼠标/触摸事件)需在useEffect中注册,并在清理函数中移除,防止内存泄漏。
  • 通过pointer-events: none确保背景动画不干扰上层内容的交互,z-10保证内容层级高于背景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:51:01