首页 > 解决方案 > 调整大小时画布反应组件闪烁

问题描述

当我调整画布组件的大小时,它会闪烁。我不太确定为什么会这样。当画布长度和宽度发生变化时,会发生调整大小。

这是我的组件:

const Cargo = styled.canvas`
width: ${props => props.width}px;
height: ${props => props.height}px;
margin-left: ${props => props.marginLeft}px;
position: relative;
`;

const Canvas = () => {

const canvasRef = useRef(null);

useEffect(() => {
  const canvas = canvasRef.current;
  const img = new Image();
  const ctx = canvas.getContext('2d');
  
  if(!canvas) {
    return;
  }
  const draw = () => {
    img.src = `${process.env.PUBLIC_URL}/images/${(cargoState.cargo_type).toLowerCase()}.jpg`;
    img.onload = function () {

    canvas.width = this.naturalWidth;
    canvas.height = this.naturalWidth;

    ctx.drawImage(img, 0, 0,  this.width, this.height);
    
  };
  }
  draw();

    
},[]);
  


return (
  <>
    <Cargo ref={canvasRef} style={{marginLeft: marginLeft}} height={cargoHeight} width={cargoWidth} />
  </>
)

}

标签: reactjscanvasreact-hookshtml5-canvasdrawimage

解决方案


闪烁是由于两个原因:

  1. 在每张图中创建一个新图像是一项昂贵的操作,所以最好使用参考,这给我带来了很多优化
  2. 大小的变化可能有点突然,特别是如果它是用鼠标滚轮完成的。所以最好是使用requestAnimationFrame。

如果您只执行第 1 步,则不会出现闪烁。

代码如下所示:

  const canvasRef = useRef(null);
  const requestRef = useRef();
  const image = useRef(null);
  const [cargoHeight, setCargoHeight] = useState(100);
  const [cargoWidth, setCargoWidth] = useState(100);

  const draw = () => {
    const canvas = canvasRef.current;
    const img = new Image();
    const ctx = canvas.getContext("2d");
    canvas.width = image.current.width;
    canvas.height = image.current.height;
    ctx.drawImage(
      image.current,
      0,
      0,
      image.current.width,
      image.current.width
    );
  };

  useLayoutEffect(() => {
    requestRef.current = requestAnimationFrame(draw);
    return () => window.cancelAnimationFrame(requestRef.current);
  }, [cargoHeight, cargoWidth]);

  return (
    <div className="App">
      <img
        src={
          "https://www.tuexperto.com/wp-content/uploads/2020/01/png.jpg.webp"
        }
        ref={image}
        style={{ display: "none" }}
      />
      <Cargo ref={canvasRef} height={cargoHeight} width={cargoWidth} />
      <button onClick={() => setCargoHeight(cargoHeight + 50)}>height</button>
      <button onClick={() => setCargoWidth(cargoWidth + 50)}>width</button>
    </div>
  );

带有解决方案和完整示例的代码框


推荐阅读