首页 > 其他分享 >低开开发笔记(八): 低代码编辑器实现撤销回退(命令模式,防抖处理)

低开开发笔记(八): 低代码编辑器实现撤销回退(命令模式,防抖处理)

时间:2024-07-16 18:32:10浏览次数:17  
标签:状态 防抖 undoStack false 低开 撤销 编辑器 context 重做

好家伙,

 

0.代码已开源

https://github.com/Fattiger4399/ph_questionnaire-.git

 

1.事件触发

我们先从事件的触发开始讲起

大致上我们有两个思路可以选择

  1.监控用户行为

  2.监控数据变化

 

两种选择都会有较难处理的部分,这里我们先选第二个选项

 

关于监控数据,首先你会想到什么?

没错,watch

watch: {
        formTemplate: {
            handler: function (oldVal, newVal) {
                if (!this.ischange) {
                    // debugger
                    console.log(oldVal, newVal)
                }
            },
            deep: true,
            immediate: true,
        }
    },

 

但是,这会出现一些问题

 深度监视

 

来看看我们数据的样子

如果我们从数据的角度出发观察变化,在拖拽的过程中,

数据由

{
    "list": [],
    "config": {
        "labelPosition": "top",
        "labelWidth": 80,
        "size": "mini",
        "outputHidden": true,
        "hideRequiredMark": false,
        "syncLabelRequired": false,
        "labelSuffix": "",
        "customStyle": ""
    }
}

 变成了

{
    "list": [
        {
            "type": "input",
            "options": {
                "defaultValue": "",
                "type": "text",
                "prepend": "",
                "append": "",
                "placeholder": "请输入",
                "maxLength": 0,
                "clearable": false,
                "hidden": false,
                "disabled": false
            },
            "label": "输入框",
            "labelWidth": -1,
            "width": "100%",
            "span": 24,
            "model": "input_17211185804812",
            "key": "input_17211185804812",
            "rules": [
                {
                    "required": false,
                    "message": "必填项",
                    "trigger": [
                        "blur"
                    ]
                }
            ],
            "dynamicLabel": false
        }
    ],
    "config": {
        "labelPosition": "top",
        "labelWidth": 80,
        "size": "mini",
        "outputHidden": true,
        "hideRequiredMark": false,
        "syncLabelRequired": false,
        "labelSuffix": "",
        "customStyle": ""
    }
}

 由于监控的是一个复杂对象,这会导致watch多次触发

 

 

2.防抖

function debounce(func, wait) {
    let timeout;
    return function () {
        const context = this;
        const args = arguments;
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            func.apply(context, args);
        }, wait);
    };
}

 

watch: {
        formTemplate: {
            handler: debounce(function (oldVal, newVal) {
                if (!this.ischange) {
                    this.undoStack.push(deepClone(oldVal))
                }
            }, 300),
            deep: true,
            immediate: true,
        }
    },

 

 

3.栈实现撤回

这里我们使用栈去做状态记录的保存

    handleUndo() {
            this.ischange = true
            if (this.undoStack.length > 1) {

                let laststate = this.undoStack[this.undoStack.length - 2]
                
                this.formTemplate = deepClone(laststate)

                let redostate = this.undoStack.pop()

                this.redoStack.push(redostate)

            } else {
                alert("撤回栈已空,无法撤回")
            }
            setTimeout(() => {
                this.ischange = false
            }, 400)
        },

        handleRedo() {
            if (this.redoStack.length > 0) {
                this.formTemplate = this.redoStack.pop()
            } else {
                alert("无法重做")
            }
        },
  • 撤销操作:

    • 将当前状态保存到重做栈中。
    • 从撤销栈中取出最后一个状态,并将其设为当前状态。
    • 从撤销栈中移除最后一个状态。
  • 重做操作:

    • 将当前状态保存到撤销栈中。
    • 从重做栈中取出最后一个状态,并将其设为当前状态。
    • 从重做栈中移除最后一个状态。

逻辑图

过程解释

  • 初始状态:

    • 空白的工作区。
    • 撤销栈是空的。
    • 重做栈是空的。
  • 用户进行第一个操作:

    • 用户在工作区添加了“元素一”。
    • 撤销栈中保存了操作前的状态(空白)。
    • 重做栈依然是空的。
  • 用户进行第二个操作:

    • 用户在工作区添加了“元素二”。
    • 撤销栈中保存了操作前的状态(元素一)。
    • 撤销栈现在有两个状态(元素一和空白)。
    • 重做栈依然是空的。
  • 用户点击撤回:

    • 撤回上一步操作,恢复到上一个状态(元素一)。
    • 撤销栈中移除最后一个状态(元素二),撤销栈现在只有一个状态(空白)。
    • 重做栈中保存被撤销的状态(元素二)。
  • 用户点击重做:

    • 重做上一步撤销的操作,恢复到上一个状态(元素一)。
    • 撤销栈中保存恢复前的状态(空白)。
    • 重做栈移除最后一个状态(元素一),现在只有一个状态(元素二)。

 

 

4.使用命令模式思想封装

最后,我们对代码进行封装

//命令类
class Command {
    constructor(execute, undo) {
        this.execute = execute;
        this.undo = undo;
    }
}
class UndoCommand extends Command {
    constructor(context) {
        super(
            () => {
                if (context.undoStack.length > 1) {
                    let laststate = context.undoStack[context.undoStack.length - 2];
                    context.formTemplate = deepClone(laststate);
                    let redostate = context.undoStack.pop();
                    context.redoStack.push(redostate);
                } else {
                    alert("撤回栈已空,无法撤回");
                }
                setTimeout(() => {
                    context.ischange = false;
                }, 400);
            },
            () => {
                if (context.redoStack.length > 0) {
                    context.formTemplate = context.redoStack.pop();
                } else {
                    alert("无法重做");
                }
            }
        );
    }
}


class RedoCommand extends Command {
    constructor(context) {
        super(
            () => {
                if (context.redoStack.length > 0) {
                    context.formTemplate = context.redoStack.pop();
                } else {
                    alert("无法重做");
                }
            },
            () => {
                // 这里可以实现撤销 redo 的逻辑,但我们暂时不需要
            }
        );
    }
}


//methods
//撤销重做
        handleUndo() {
            this.ischange = true;
            const undoCommand = new UndoCommand(this);
            undoCommand.execute();
        },
        handleRedo() {
            const redoCommand = new RedoCommand(this);
            redoCommand.execute();
        },

 

标签:状态,防抖,undoStack,false,低开,撤销,编辑器,context,重做
From: https://www.cnblogs.com/FatTiger4399/p/18305653

相关文章

  • 组态软件之万维组态介绍(web组态、html组态、vue2/vue3组态、组态软件、组态编辑器)
     一、什么是组态软件组态软件是一种用于创建、配置和管理监控和控制系统的软件工具。组态是指不需要编写计算机程序、通过配置的方式完成工业应用开发的系统。它们通常用于工业自动化领域,用于实时监视和控制工业过程。组态软件提供了丰富的功能和工具,使用户能够创建用户界......
  • 假阴影,低开销的阴影实现方式
    参考:Unity无光照假阴影Shader实现及常见问题总结-简书(jianshu.com) 游戏实现阴影的常见处理方式(动态人或物,非烘焙)1.实时光照实时光照属于真阴影,一般来说效果是最好的,但是开销也是最大的。 ShadowMap(阴影贴图)跟SoftShadows(软阴影)-JeasonBoy-博客园(cn......
  • 为什么PyCharm是首选的Python代码编辑器?
    这两年被Python初学小白问到最多的问题就是,该用什么代码编辑工具?说实话,我个人是用JupyterNotebook最多,主要是经常做数据可视化,方便些。但对于初学者来说,PyCharm仍是不二的选择,甚至我建议你只用PyCharm.从当前所有主流PythonIDE来看,PyCharm是最适合做Python开发的,特别对......
  • Windows 注册表编辑器(regedit)的演变和发展主要是由 Microsoft Windows 操作系统的设计
    Windows注册表编辑器(regedit)的演变和发展主要是由MicrosoftWindows操作系统的设计和需求驱动的。下面是大致的演化过程:需求和设计:在早期的Windows系统中,配置信息分散存储在各种配置文件和INI文件中,管理起来不够方便。为了统一管理系统配置信息,并提高系统的灵活性和可维......
  • 福昕高级PDF编辑器专业版2024.2.0安装教程
    1、下载安装包2、双击安装程序进行安装3、修改安装位置,点击安装4、等待安装5安装完成,一定不能立即启用不要点击立即启用6、将patch的应用程序放到安装目录下面,双击启动7、点击应用8、执行完成,打开软件就可以用了如遇到福昕高级PDF编辑器失败,提示:本机已安装......
  • Vim:最受欢迎的编辑器之一
    目录前言1.Vim的基本情况1.1Vim的起源与发展1.2Vim的工作模式2.Vim受欢迎的原因2.1强大的功能2.1.1丰富的快捷键2.1.2高度可定制化2.1.3强大的插件系统2.2使用方便性2.2.1跨平台支持2.2.2轻量级和高效2.2.3离线操作3.Vim与其他编辑器的比较3.1与现代ID......
  • 帝国CMS网站的编辑器默认会清除多余的word代码,如果要保留word格式怎么修改?
    编辑器默认会清除多余的word代码,如果要保留word格式怎么修改?答:CKeditor编辑器默认复制会清除多余word代码,如果要保留word格式可以按下面修改配置:修改/e/admin/ecmseditor/infoeditor/config.js(后台)和/e/data/ecmseditor/infoeditor/config.js(前台)文件,找到:config.toolba......
  • 【unity开发】怎么下载国际版的unity编辑器版本
    有一天从公司那接手了一个项目,然后发现那个项目的版本我没有,我就去unity官网下载。下载完了发现还是版本不对。仔细一看发现,他们用的版本号末尾少了个"c1"。c1的意思是中国特供版,好像是说有微信api的支持。那么我应该怎么做呢?下面随便一个版本为例子1.点击按钮下载。2.......
  • 【嵌入式】linux开发笔记:编辑器vi的基本指令
    ‘vi的使用’:Linux中常用的文本编辑器vi的使用方法。包括’模式’、‘输入模式’、‘按键入’、‘看到insert就能编辑代码’、‘退出vi保存代码’等。‘gcc编译工具’:这部分介绍了Linux中常用的编译工具gcc的使用方法。包括’运行’、’./程序名’等。‘文件管理’:这部......
  • 理解 Linux 文件权限(2)& vim编辑器
    1、如何理解文件权限1)查看文件• 想要理解文件权限,需要先从查看文件入手•使用ls–l命令查看Linux系统上的文件、目录和设备的权限①对象的类型②文件属性③目录/链接个数④所有者(owner)⑤组(group)⑥文件大小⑦最后修改的日期⑧文件名其中:• ①代表了对象的类型:......