最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • (开源)给图片编辑器添加了【撤销重做】功能

    正文概述 掘金(杰出D)   2021-08-20   699

    本文已参与掘金创作者训练营第三期,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力。

    前言

    上篇文章我们实现了图片编辑器的辅助线,大多数的工具类型软件都支持撤销和重做,趁热打铁,我们图片编辑器的撤销重做的功能给实现一下,丰富我们的图片编辑器的功能。

    演示

    演示地址

    (开源)给图片编辑器添加了【撤销重做】功能

    实现流程

    原理讲解

    通过上面的演示我们分析有这三种类型的操作,分别是push,undo,redo

    1. 在操作的过程中记录状态push

    (开源)给图片编辑器添加了【撤销重做】功能 通过流程图我们可以看到,正常的操作直接记录状态就可以。

    2.在操作过程中撤销操作undo

    (开源)给图片编辑器添加了【撤销重做】功能 通过流程图我们可以看到在撤销1操作后,当前的状态会到操作2的状态。在进一步点击撤销2会回到操作1的状态

    3.在操作过程中执行重做操作rudo

    (开源)给图片编辑器添加了【撤销重做】功能 通过流程图我们可以看到在操作重做1后,图片会回到操作2的状态。

    4.继续在操作的过程中记录状态again push

    (开源)给图片编辑器添加了【撤销重做】功能

    注意:此时我们可以有两种操作,一是继续点击重做,图片会回到操作3的状态。这个我们就不画流程图了。另一种可以直接在操作图片内的元素,此时要把操作3的状态记录给移除掉.流程图如下:

    代码实现

    大致思路是,我们用了状态管理库,通过快照的方式,在状态变更的过程中记录到数组中,撤销的时候通过索引执向要显示的状态,重做的时候也是通过索引回复到之前状态状态。在继续操作的时候,可能会删除部分状态

    定义保存记录的数据结构

    // 撤销重做数据结构
    undoRedoData: {
        activeSnapshot: null, // 当前激活的快照数据
        snapshots: [], // 存储的快照数据
        current: -1, // 当前索引
    }
    

    更新快照数据

    • 我们定义了操作的类型type, 分别是push,undo,redo
    // 操作类型
    export type UndoRedoActionType = {
      type: 'push' | 'undo' | 'redo';
      data: DatModelItem | null;
    };
    
    
    • 执行push操作代码内容为
    if (type === 'push') {
        // 深度拷贝要保存的记录
        const newData = _.cloneDeep(data);
        if (current === -1) {
          newUndoRedoData.snapshots = [...snapshots, newData];
        } else {
          // 当前已经撤销,重新操作的时候要把某些记录取消
          newUndoRedoData.snapshots = snapshots
            .slice(0, current)
            .concat([newData]);
        }
        // 重置当前激活的数据和索引
        newUndoRedoData.activeSnapshot = null;
        newUndoRedoData.current = -1;
    }
    

    注意:由于我们用了flooks状态库,它目前不支持不可变数据,所以我们在报存记录的时候用了深拷贝,这里性能会有影响。如果不深拷贝,对象应用传递,会引发bug。之后我们会改造这个flooks,让他支持不可变数据。

    • 执行undo操作代码内容为
     if (type === 'undo') {
        // 第一次执行撤销操作
        if (current === -1) {
          newUndoRedoData.current = snapshots.length - 1;
        } else { // 连续执行撤销操作
          newUndoRedoData.current = current - 1;
        }
        // 设置当前激活的快照数据
        newUndoRedoData.activeSnapshot = snapshots[newUndoRedoData.current];
    }
    
    • 执行redo操作代码内容为
    if (type === 'redo') {
        // 可以执行重做操作
        if (current != -1) {
          newUndoRedoData.current = current + 1;
        }
        // 重做操作已经到最后一步,重置激活的状态和索引
        if (current === snapshots.length - 1) {
          newUndoRedoData.activeSnapshot = null;
          newUndoRedoData.current = -1;
        } else {
          newUndoRedoData.activeSnapshot = snapshots[newUndoRedoData.current];
        }
    }
    

    设置阈值,避免内存爆栈

    我们一直是在往数组里添加记录,没有做上线判断,操作多的情况下可能会引发内存爆栈。设置阈值来判断记录上线。代码如下

    //阈值设置100,最多报错100次操作
    let threshold = 100;
    // 快照数据大于阈值
    if (newUndoRedoData?.snapshots?.length > threshold) {
        //保留最后的100条数据
        newUndoRedoData.snapshots = newUndoRedoData.snapshots.splice(-threshold);
    }
    

    这里用了Arraysplice方法,改方法负值会从后向前截取。

    页面逻辑

    • 撤销回退按钮
     <Tooltip placement="bottom" >
      <Button
        onClick={undo}
        disabled={
          undoRedoData.snapshots.length === 0 || undoRedoData.current === 0
        }
        icon={<UndoOutlined />}
      />
    </Tooltip>
    <Tooltip placement="bottom" >
      <Button
        disabled={undoRedoData.current === -1}
        onClick={redo}
        icon={<RedoOutlined />}
      />
    </Tooltip>
    

    这里主要注意下禁用的判断条件。

    • 主页面渲染
    const getJsx = () => {
        // 有激活的快照数据说明有撤销或者重做的操作
        const data = undoRedoData.activeSnapshot || nodes;
        return data.map((item: DatModelItem) => {
          return getJsxItem(item);
        });
    };
    

    地址

    • 演示地址
    • 代码地址

    交流沟通

    建立了一个微信交流群,如需沟通讨论,请加入。

    (开源)给图片编辑器添加了【撤销重做】功能

    二维码过期,请添加微信号q1454763497,备注image editor,我会拉你进群

    总结

    以上我们实现了编辑器的撤销和重做,需要注意的是我们最好要用不可变数据,用深拷贝性能不好,最好用immer,后期我们会改造。功能部分大致代码介绍上面已经描述出来,如需要查看更详细的内容,请移步fast-image-editor。 大家觉得有帮忙,请在github帮忙star一下。

    历史文章

    • (开源)两个周末写了个图片编辑器
    • (开源)给图片编辑器添加了辅助线

    起源地下载网 » (开源)给图片编辑器添加了【撤销重做】功能

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元