undo-redo 实现思路

  1. 用一个数组保存栈,保存每一步的操作
  2. 需要一个指针 currentIndex: 0
  3. onChange,数组 push值,更新指针 index++;
    1. undo回退之后,再执行新的操作,需要清除当前下标之后所有的历史数据
  4. undo, index—;
  5. redo, index++;
  6. 监听键盘事件,判断 undo ctrl+z 和 redo ctrl+y 快捷键

image.png

  • 从E回退到C ,然后执行了新的操作F,那么D E 需要从记录队列中删除,F加入到C之后
  • F之后回退到C,还能够再 redo到F
  • 队列达到最大值之后,每从队尾加一个,就需要从队首剔除一个

2个栈实现

用 undo,和 redo栈实现
https://blog.csdn.net/sawa123/article/details/121821025
image.png

  1. import { cloneDeep } from 'lodash';
  2. import { useModel } from 'umi';
  3. // 最大回退操作步骤
  4. const maxStep = 60;
  5. const undoQueue = [];
  6. let redoQueue = [];
  7. function useUndo() {
  8. const { components, setComponents } = useModel('visualPage');
  9. const saveSnap = () => {
  10. const snap = cloneDeep(components);
  11. if (undoQueue.length >= maxStep) {
  12. undoQueue.shift();
  13. }
  14. undoQueue.push(snap);
  15. // console.log('queue', undoQueue, redoQueue);
  16. // 注意!!每次执行命令时清空重做栈
  17. redoQueue = [];
  18. };
  19. const undo = () => {
  20. const snap = cloneDeep(components);
  21. const c = cloneDeep(undoQueue[undoQueue.length - 1]);
  22. setComponents(c);
  23. redoQueue.push(snap);
  24. undoQueue.pop();
  25. };
  26. const redo = () => {
  27. const snap = cloneDeep(components);
  28. const c = cloneDeep(redoQueue[redoQueue.length - 1]);
  29. setComponents(c);
  30. undoQueue.push(snap);
  31. redoQueue.pop();
  32. };
  33. return {
  34. saveSnap,
  35. undo,
  36. redo,
  37. undoQueue,
  38. redoQueue,
  39. };
  40. };
  41. export default useUndo;