首页 > 解决方案 > 在 React 中使画布适合屏幕

问题描述

所以我有这个代码库:

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

function App() {
  const container = useRef(null);
  const canvas = useRef(null);

  const [ctx, setCtx] = useState(undefined);

  useEffect(() => {
    setCtx(canvas.current.getContext("2d"));
  }, []);

  useEffect(() => {
    if (!ctx) return;

    ctx.fillStyle = 'green';
    ctx.fillRect(0, 0, canvas.current.width, canvas.current.height);
  }, [ctx]);

  return (
    <div
      style={{
        height: "100vh",
        display: "flex",
        flexDirection: "column",
        padding: 8,
        position: "relative",
      }}
    >
      <header>
        Some Header
      </header>
      <div style={{ margin: 40, flex: '1 1' }} ref={container}>
        <canvas ref={canvas} />
      </div>
    </div>
  );
}

export default App;

这是放置在容器 div 内的画布元素的非常基本的示例。

我想要做的是根据用户的屏幕调整画布的宽度和高度(并使其具有响应性)。

所以我发现了两个选择:

使用window.addEventListener('resize', ...)或使用ResizeObserver

我尝试了它们,但没有任何成功,这就是我试图做的:

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

function App() {
  const container = useRef(null);
  const canvas = useRef(null);

  const [ctx, setCtx] = useState(undefined);
  const [size, setSize] = useState([0, 0]);

  useEffect(() => {
    const resize = () => {
      const { offsetWidth, offsetHeight } = container.current;

      canvas.current.width = offsetWidth;
      canvas.current.height = offsetHeight;

      setSize([offsetWidth, offsetHeight]);
      setCtx(canvas.current.getContext('2d'));
    };

    resize();
    window.addEventListener('resize', resize);

    return () => window.removeEventListener('resize', resize);
  }, []);

  useEffect(() => {
    if (!ctx) return;

    ctx.fillStyle = 'green';
    ctx.fillRect(0, 0, size[0], size[1]);
  }, [ctx, size]);

  return (
    <div
      style={{
        height: "100vh",
        display: "flex",
        flexDirection: "column",
        padding: 8,
        position: "relative",
      }}
    >
      <header>
        Some Header
      </header>
      <div style={{ margin: 40, flex: '1 1' }} ref={container}>
        <canvas ref={canvas} style={{ width: size[0], height: size[1] }} />
      </div>
    </div>
  );
}

export default App;

但由于某种原因,它使画布的高度在每个调整大小循环中都更大。

为什么会这样,我该如何解决?

标签: reactjscanvas

解决方案


如果您使用画布包没有问题,您可以使用react-konva它可以很好地处理响应性。

因此,您所要做的就是在调整窗口大小时更改高度和宽度,并将它们作为属性发送。

...
useEffect(() => {
 const checkSize = () => {
  setSize({
   width: window.innerWidth,
   height: window.innerHeight
  });
 };
 window.addEventListener("resize", checkSize);
 return () => window.removeEventListener("resize", checkSize);
}, []);

...

return (
 <Stage
  width={size.width}
  height={size.height}
 >
  ...
 </Stage>
)
...

演示:codesandbox


推荐阅读