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

基于滚动事件监听的CSS文本动画实现求助(仿viraly.com.br)

实现视口触发的文本滚动动画(LTR/RTL)

需求说明

需要实现两种文本滚动入场动画:

  • LTR(从左到右):初始位置为-200vh,元素进入视口后滚动到原位
  • RTL(从右到左):初始位置为164vh,元素进入视口后滚动到原位
    滚动到元素进入视口范围时触发动画,现有Next.js代码效果未达预期,需修正实现逻辑。

现有代码问题分析

  1. DOM查询时机错误:在组件顶层直接调用document.querySelectorAll,Next.js的SSR阶段会报错,且组件重渲染时会重复执行查询,未绑定到正确的组件生命周期。
  2. 滚动监听性能低下:使用scroll事件监听,触发频率极高,易引发页面性能问题。
  3. 可见性判断过严:仅当元素完全进入视口才触发动画,不符合常规的用户体验逻辑(通常元素部分进入视口就应启动动画)。
  4. 无监听清理机制:滚动监听未在组件卸载时移除,会造成内存泄漏。
  5. CSS优先级不足:重置类的transform属性优先级低于初始动画类,可能导致动画状态切换失效。

修正后的实现代码

Next.js 组件代码

'use client' // Next.js 13+ App Router 需添加此指令
import { useEffect, useRef } from 'react';

export function HartechAnimated() {
  const containerRef = useRef(null);

  useEffect(() => {
    // 配置交叉观察器参数
    const observerOptions = {
      root: null,
      rootMargin: '0px',
      threshold: 0.1 // 元素10%进入视口时触发动画
    };

    // 交叉观察器回调逻辑
    const observerCallback = (entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const target = entry.target;
          if (target.classList.contains('animateRTL')) {
            target.classList.add('resetXRTL');
          } else if (target.classList.contains('animateLTR')) {
            target.classList.add('resetXLTR');
          }
          // 仅触发一次动画,避免重复执行
          observer.unobserve(target);
        }
      });
    };

    // 初始化交叉观察器
    const observer = new IntersectionObserver(observerCallback, observerOptions);
    const animateElements = containerRef.current?.querySelectorAll('.animateRTL, .animateLTR');

    // 为目标元素添加监听
    if (animateElements) {
      animateElements.forEach(el => observer.observe(el));
    }

    // 组件卸载时清理监听
    return () => {
      if (animateElements) {
        animateElements.forEach(el => observer.unobserve(el));
      }
    };
  }, []);

  return (
    <div 
      ref={containerRef}
      className="font-britanica-black-expanded overflow-hidden text-6xl text-white py-20 md:text-black md:text-9xl md:py-36"
    >
      <b className="block animateLTR">HARTECH REPARO</b>
      <b className="block hartech-stroke animateRTL">DE PLACAS DE VÍDEO</b>
      <b className="block animateLTR">HARTECH REPARO</b>
    </div>
  );
}

CSS 代码

/* 初始动画状态 */
.animateRTL {
  transform: translateX(164vh);
  transition: transform 2.2s ease-in-out;
}

.animateLTR {
  transform: translateX(-200vh);
  transition: transform 2s ease-in-out;
}

/* 重置状态(通过组合选择器提高优先级) */
.animateRTL.resetXRTL,
.animateLTR.resetXLTR {
  transform: translateX(0);
}

关键改进说明

  • 采用Intersection Observer:替代传统滚动监听,性能更优,可通过threshold精准控制动画触发时机。
  • 规范组件生命周期:在useEffect中处理DOM操作与监听逻辑,确保仅在客户端执行,组件卸载时自动清理监听,避免内存泄漏。
  • 优化CSS优先级:使用组合选择器提升重置类的优先级,确保动画状态切换生效。
  • 单次动画触发:元素进入视口后停止监听,避免重复触发动画,符合预期交互逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:50:15