这样的官网怎么样❓续集源码篇

1,053 阅读4分钟

背景

在上一篇文章 《这样的官网怎么样❓》 中,我们初步了解了该官网的整体设计,并与大家探讨了它的视觉呈现和用户体验。

我们前期的内部设计偏向简洁,所以开始思考如何提升网站的整体设计感。这些尝试便由此展开。

网站地址:infinilabs.com/

如果你对动态背景的实现感兴趣,这篇文章将带你深入探索,揭秘如何从零打造一个兼具美感与功能性的企业官网!

技术选型

  • 前端框架:Next.js
  • UI 框架:基于 Tailwind CSS
  • CSS 样式:Tailwind CSS(快速开发、内置响应式、丰富工具类)

为什么选择 Next.js?

  1. 兼容团队技术栈:基于 React,便于团队协作。
  2. SEO 和性能优化:支持服务端渲染(SSR)和静态站点生成(SSG)。
  3. 路由强大:支持动态路由和文件路由,灵活易用。
  4. 内置优化:图片优化、国际化、多种性能提升。
  5. 动态内容支持:博客、新闻等动态场景轻松应对。
  6. 加载体验佳:用户体验和页面加载速度表现优秀。

动态的背景方案

动态背景可以显著提升视觉吸引力,以下是常用实现方案:

  1. CSS 动画背景:使用纯 CSS 实现动态背景,通过 @keyframes 配合渐变色、位置移动等属性。
  2. 动态 Canvas 背景:使用 <canvas> 元素,结合 JavaScript 绘制动态效果,比如粒子系统、波浪效果等。
  3. 动态视频背景:使用 <video> 元素播放循环视频作为背景。
  4. WebGL 动态背景:使用 WebGL 库(如 Three.js)渲染 3D 动态背景。
  5. 动态粒子背景:使用现有的粒子背景库快速实现动态粒子效果。(particles.js 或 tsparticles)
  6. ......

如何选择?

  1. 简单需求: 纯 CSS 动画、动态视频背景。
  2. 复杂交互:Canvas 动画、WebGL 动画(Three.js)。
  3. 快速实现:使用粒子背景库(particles.js / tsparticles)。

动态背景代码实现

以下示例通过 WebGL 创建了一个动态背景组件,支持 React 和 Tailwind CSS。

  1. 创建 GlobalBackground.tsx 文件:
'use client'

import dynamic from 'next/dynamic'
import { Suspense, useEffect, useState } from 'react'
import { Layout } from './Layout'

const ShaderGradient = dynamic(() => import('shadergradient').then((mod) => mod.ShaderGradient), { ssr: false })
const View = dynamic(() => import('./View').then((mod) => mod.View), {
  ssr: false,
  loading: () => (
    <div className='w-full h-full bg-cover bg-center' style={{ backgroundImage: 'url(/images/loading-bg.png)' }}>
    </div>
  ),
})

export default function GlobalBackground() {
  const defaultProps: any = {
    control: "props",
    animate: "on",
    brightness: 1.2,
    cDistance: 3.6,
    cameraZoom: 1,
    color1: "#0600B8",
    color2: "#9000E3",
    color3: "#0B004F",
    // embedMode: "off",
    envPreset: "city",
    // gizmoHelper: "hide",
    grain: "off",
    lightType: "3d",
    reflection: 0.1,
    shader: "defaults",
    type: "waterPlane",
    uSpeed: 0.2,
    uTime: 0,
    wireframe: false,
    zoomOut: false,
    toggleAxis: false,
  }

  const [suspenseWebgl, setSuspenseWebgl] = useState(false)
  useEffect(() => {
    const canvas = document.createElement("canvas");
    const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
    if (gl) {
        // 浏览器支持 WebGL
        console.log('The browser does support WebGL')
        setSuspenseWebgl(true)
    } else {
      console.log('The browser does not support WebGL')
      // 浏览器不支持 WebGL
    }
  }, []);
  return (<>
      {suspenseWebgl ? <Layout>
        <View className='w-full h-full'>
          <Suspense fallback={null}>
            <ShaderGradient {...defaultProps} />
          </Suspense>
        </View>
      </Layout> : null}
    </>)
}
  1. 创建 Layout.tsx 文件:
'use client'

import { useRef } from 'react'
import dynamic from 'next/dynamic'
const Scene = dynamic(() => import('./Scene'), { ssr: false })

const Layout = ({ children }: any) => {
  const ref = useRef<any>()

  return (
    <div
      ref={ref}
      className='fade-in'
      style={{
        position: 'fixed',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%',
        zIndex: -1,
        overflow: 'auto',
        touchAction: 'auto',
      }}
    >
      {children}
      <Scene
        style={{
          position: 'fixed',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
          pointerEvents: 'none',
        }}
        eventSource={ref}
        eventPrefix='client'
        pixelDensity={1}
        pointerEvents='none'
      />
    </div>
  )
}

export { Layout }
  1. 创建 Scene.tsx 文件:
'use client'

import { ShaderGradientCanvas } from 'shadergradient'
import { Canvas } from '@react-three/fiber'
import { Preload } from '@react-three/drei'
import tunnel from 'tunnel-rat'

const r3f = tunnel()

export default function Scene({ ...props }) {
  // Everything defined in here will persist between route changes, only children are swapped

  return (
    <ShaderGradientCanvas {...props}>
      {/* @ts-ignore */}
      <r3f.Out />
      <Preload all />
    </ShaderGradientCanvas>
  )
}

  1. 创建 View.tsx 文件:
'use client'

import { forwardRef, Suspense, useImperativeHandle, useRef } from 'react'
import { OrbitControls, PerspectiveCamera, View as ViewImpl } from '@react-three/drei'
import tunnel from 'tunnel-rat'

const r3f = tunnel()

const Three = ({ children } : any) => {
  return <r3f.In>{children}</r3f.In>
}

export const Common = ({ color }: any) => (
  <Suspense fallback={null}>
    {color && <color attach='background' args={[color]} />}
    <ambientLight intensity={0.5} />
    <pointLight position={[20, 30, 10]} intensity={1} />
    <pointLight position={[-10, -10, -10]} color='blue' />
    <PerspectiveCamera makeDefault fov={40} position={[0, 0, 6]} />
  </Suspense>
)

const View = forwardRef(({ children, orbit, ...props }: any, ref) => {
  const localRef = useRef<any>(null)
  useImperativeHandle(ref, () => localRef.current)

  return (
    <>
      <div ref={localRef} {...props} />
      <Three>
        <ViewImpl track={localRef}>
          {children}
          {orbit && <OrbitControls />}
        </ViewImpl>
      </Three>
    </>
  )
})
View.displayName = 'View'

export { View }
  1. 直接在 app/page.tsx 使用背景组件:
import GlobalBackground from "@/components/GlobalBackground";

export default function Home() {
  return (
    <>
      <GlobalBackground></GlobalBackground>
      <div
        className="min-h-screen bg-cover bg-center"
        style={{ backgroundImage: "url(/svg/bg_n.svg)" }}
      >
        ....
      </div>
    </>
  );
}

  1. 当然,代码弄好了,要想让代码运行起来,还需要安装一下依赖:
pnpm add @react-three/drei @react-three/fiber shadergradient tunnel-rat

通过这些步骤,你将能够为网站实现高性能、响应式的动态背景效果。根据具体需求调整背景类型和交互复杂度,让你的官网更具吸引力!

效果图

tu23.gif

分享

如果你也想配置自己的动态效果图,可以前往 shadergradient.co 网站进行自定义设置。完成后,将生成的配置参数复制到 GlobalBackground.tsx 文件的 defaultProps 中,即可实现属于你自己的动态背景效果。

参考

福利

INFINILabs一直致力于为开发者和企业提供优质的开源工具,提升整个技术生态的活力。除了维护国内最流行的分词器 analysis-ikanalysis-pinyin,也在不断推动更多高质量开源产品的诞生。

最近新开源的产品和工具:

以上开源软件都可以在 Github 上面找到: github.com/infinilabs

希望大家都能给个免费的 Star🌟 支持一下!!!