当前位置: 首页 > 知识库问答 >
问题:

javascript - React 中,一个根据文本量自动放缩的组件,怎么减少动画闪烁?

仲法
2024-07-30

React 中,一个根据文本量自动放缩的组件,怎么减少动画闪烁?

import { useState, useEffect, useRef, FC } from 'react';

const AutoScalingText: FC<{ text: string }> = ({ text }) => {
  const [scale, setScale] = useState(1);
  const nodeRef = useRef<HTMLDivElement>(null);
  const parentNodeOffsetWidth = useRef<number>(0); //全局变量,免得每次都重新计算parentNodeOffsetWidth

  useEffect(() => {
    parentNodeOffsetWidth.current = (
      nodeRef.current!.parentNode as HTMLElement
    ).offsetWidth;
  }, []);

  useEffect(() => {
    const node = nodeRef.current;
    if (!node) return;

    // 每次text变化时,根据文本长度设定scale 范围
    const availableWidth = parentNodeOffsetWidth.current - 32;
    const actualWidth = node.offsetWidth;
    const actualScale = availableWidth / actualWidth;
    if (scale !== actualScale) {
      if (actualScale < 1) {
        setScale(actualScale);
      } else if (scale < 1) {
        setScale(1);
      }
    }
  }, [text]);

  return (
    <div
      className='auto-scaling-text'
      style={{ transform: `scale(${scale},${scale})` }}
      ref={nodeRef}
    >
      {text}
    </div>
  );
};

export default AutoScalingText;

求求了!
在线demo,可能在审核中:https://inscode.csdn.net/@weixin_41983540/React-TypeScript-Te...

共有1个答案

解念
2024-07-30

在React中,减少动画闪烁的一个常见方法是确保DOM更新和样式变化尽可能平滑且高效。对于你的AutoScalingText组件,闪烁可能由于以下几个原因引起:

  1. 频繁的重渲染:每次文本变化时,组件都会重新计算scale并触发重渲染。
  2. 布局抖动:当scale变化时,可能会触发父容器的重新布局,进而影响子元素的尺寸,形成一个循环。
  3. CSS动画或变换的即时性transform属性的即时变化可能导致视觉上的不连续。

为了减少闪烁,你可以尝试以下策略:

1. 使用requestAnimationFrame

将scale的更新放在requestAnimationFrame中,这可以确保DOM的更新与浏览器的重绘和回流同步,从而可能减少闪烁。

useEffect(() => {
  const updateScale = () => {
    const node = nodeRef.current;
    if (!node) return;

    const availableWidth = parentNodeOffsetWidth.current - 32;
    const actualWidth = node.offsetWidth;
    const actualScale = availableWidth / actualWidth;
    if (scale !== actualScale) {
      if (actualScale < 1) {
        setScale(actualScale);
      } else if (scale < 1) {
        setScale(1);
      }
    }
  };

  window.requestAnimationFrame(updateScale);
}, [text, scale, parentNodeOffsetWidth.current]);

注意,这里将parentNodeOffsetWidth.current也加入了依赖数组,因为parentNodeOffsetWidth可能也会变化(尽管在你的例子中它被设置为只计算一次)。

2. 防抖(Debouncing)或节流(Throttling)

如果文本变化非常频繁,你可以考虑使用防抖或节流技术来减少重计算的频率。但在这个场景中,由于scale的计算依赖于DOM的实际尺寸,这可能不是最佳选择。

3. 优化CSS

确保CSS样式尽可能高效。例如,使用will-change属性来提示浏览器该元素可能会改变其变换,这可以优化性能。

.auto-scaling-text {
  will-change: transform;
}

4. 考虑使用CSS的font-size调整而非transform: scale()

如果可能的话,考虑使用CSS的font-size来直接调整文本大小,而不是通过transform: scale()。这可以避免一些与变换相关的性能问题。

5. 使用React的useLayoutEffect

如果scale的更新需要立即反映在DOM上,并且你希望这些更新在浏览器绘制之前完成,可以使用useLayoutEffect代替useEffect。但在这个例子中,useEffect加上requestAnimationFrame应该足够了。

结论

对于你的特定情况,使用requestAnimationFrame来同步DOM更新和样式变化可能是减少闪烁的最有效方法。同时,确保你的CSS样式和React组件的逻辑尽可能高效。

 类似资料:
  • 有两个div 想要实现.two在.one这个div里面通过滚轮缩放和鼠标拖动效果,并且拖动过程中不能完全拖离.one这个的区域,至少保留20px还在区域内(不管上下左右拖动都一样)意思大概跟下面这张图一样 而且.two初始的宽高大于.one,在打开这个页面的时候要把.two缩放到.one可显示全的大小,不知道这个效果该怎么做,搞了好久搞不出来,现在做了一部分,代码如下:

  • 我正在用Java编写一个数独游戏,我想把新游戏的动作制作成动画,如下所示: 一旦用户点击开始游戏,每个元素就开始从左上角到右下角依次出现。 动画应该以彼此100毫秒的延迟开始,而不是同时进行。比如从60%到100%,然后完成每个元素的动画。 我将谜题模型加载到JPanel中的代码是: puzzle对象的数字从1到300,对应于图像,所以在创建ImageButtonMyImages时使用它。“thi

  • 大佬们这样设置在边界点会一直抖动怎么办?我就想在鼠标悬浮的时候元素向上,并且这个向上有个渐变效果,不那么生硬

  • 问题内容: 我需要使用matplotlib获取一个自动拟合数据的图。这是我得到的代码: 这样就创建了一个图,但是无论数据是什么,窗口都始终是相同的(0-〜.8),即使所有数据都在该窗口之外。生成的窗口无法放大,只能放大,因此这是一个主要问题。我找不到在任何地方设置任何类型的大小设置的地方,II也找不到关于默认值的详细信息。我需要一个窗口来自动拟合数据,但是我找不到能执行此操作的任何函数(由于某些原

  • 我有HTML页面,其中我正在使用javascript语法更改字体大小 当我尝试更改字体大小时,HTML会根据字体的增加/减少上下移动文本,用户无法保持更改字体大小之前的相同文本。 我怎样才能让用户留在原来的地方?

  • 问题内容: 所以我运行代码,它就开始不正常了。我不熟悉pygame。 代码如下: 这张图片并不是我不能发布视频的那个,但它确实是我的代码的作用 问题答案: 问题是由多次调用 . 在应用程序循环结束时更新显示就足够了。 多次调用or原因 忽隐忽现。 删除对的所有呼叫从你的代码,但调用一次 在应用程序循环结束时: 如果在之后更新显示,将显示在短时间内填充了背景色。然后玩家被抽中 ()显示时,播放器位于