Skip to main content

如何在 React 中实现画布的撤销/重做功能?

要在 React 中实现撤销/重做功能,您不需要使用 Konva 的序列化和反序列化方法。

您只需要保存应用程序中所有状态更改的历史记录。有很多方法可以做到这一点。如果使用不可变结构,可能会更简单。

说明:尝试通过拖动移动正方形。然后使用“撤销”和“重做”按钮来撤销或重放您的操作。

import React, { Component } from 'react';
import { Stage, Layer, Rect, Text } from 'react-konva';


const App = () => {
  const [position, setPosition] = React.useState({ x: 20, y: 20 });
  // 我们使用 refs 来保持历史记录,以避免不必要的重新渲染
  const history = React.useRef([{ x: 20, y: 20 }]);
  const historyStep = React.useRef(0);

  const handleUndo = () => {
    if (historyStep.current === 0) {
      return;
    }
    historyStep.current -= 1;
    const previous = history.current[historyStep.current];
    setPosition(previous);
  };

  const handleRedo = () => {
    if (historyStep.current === history.current.length - 1) {
      return;
    }
    historyStep.current += 1;
    const next = history.current[historyStep.current];
    setPosition(next);
  };

  const handleDragEnd = (e) => {
    // 在当前步骤之后移除所有状态
    history.current = history.current.slice(0, historyStep.current + 1);
    const pos = {
      x: e.target.x(),
      y: e.target.y(),
    };
    // 添加新状态
    history.current = history.current.concat([pos]);
    historyStep.current += 1;
    setPosition(pos);
  };

  return (
    <Stage width={window.innerWidth} height={window.innerHeight}>
      <Layer>
        <Text text="撤销" onClick={handleUndo} />
        <Text text="重做" x={40} onClick={handleRedo} />
        <Rect
          x={position.x}
          y={position.y}
          width={50}
          height={50}
          fill="black"
          draggable
          onDragEnd={handleDragEnd}
        />
      </Layer>
    </Stage>
  );
};

export default App;