当前位置: 首页 > news >正文

web架构师编辑器内容-添加自动保存的功能

对于频繁改动的应用,自动保存的功能是一个非常有用的功能,可以避免用户在没有保存的情况下丢失自己保存过的数据。
对于自动保存,一般有两种实现,参考语雀和石墨:

  • 语雀采用的是定时保存的方式,大约在3分半后自动发送一次请求
  • 石墨文档采用的是实时保存:对于文本区域,直接输入字符的时候,会发送请求,就是在文本区域onchange的时候,绑定一个事件,有新内容介入的时候发送请求。

这里我们可以采用第一种方法,定时发送请求。采用这种方式之前我们可以进行一个优化:为了避免一股脑的发送请求,比如说如果用户没有做任何操作,到时候还是会发送请求,所以呢,我们要给他添加一个特殊字段isDirty,这个字段可以标记一次数据是否有修改,加入有修改,才进行保存,这里采用的方式和做历史数据功能的方式类似,不会采用对比新旧数据比较耗时的方法,而是触发特定的mutations才会标记字段,比如说addComponentdeleteComponentupdateComponentupdatPage

// 特殊字段
isDirty// 在一些 mutation 的时候同时修改该字段
addComponent
deleteComponent
updateComponent
updatePagestate.isDirty = true// 在 save 之后将 isDirty 置为 false
state.isDirty = false

代码实现:添加isDirty字段

// store/editor.ts
export interface EditorProps {// 供中间编辑器渲染的数组components: ComponentData[];// 当前编辑的是哪个元素,uuidcurrentElement: string;// 当然最后保存的时候还有有一些项目信息,这里并没有写出,等做到的时候再补充page: PageData;// 当前被复制的组件copiedComponent?: ComponentData;// 当前操作的历史记录histories: HistoryProps[];// 当前历史记录的操作位置historyIndex: number;// 开始更新时的缓存值cachedOldValues: any;// 保存最多历史条目记录数maxHistoryNumber: number;// 数据是否有修改isDirty: boolean;
}

然后在一系列mutations中给isDirty设置为true,这都是一系列重复的功能,这时候就想到之前使用过的高阶函数处理过浏览器的默认行为:web架构师编辑器内容-快捷键操作的实现,这里我们也可以封装成高阶函数来完成一系列操作,比较方便:

// store/editor.ts
const setDirtyWrapper = (callback: Mutation<EditorProps>) => {return (state: EditorProps, payload: any) => {state.isDirty = true;callback(state, payload);};
};// mutations
// 添加元素
addComponent: setDirtyWrapper((state, component: ComponentData) => {component.layerName = "图层" + (state.components.length + 1);state.components.push(component);pushHistory(state, {id: uuidv4(),componentId: component.id,type: "add",data: cloneDeep(component),});
})// 粘贴元素
pasteCopiedComponent: setDirtyWrapper((state) => {if (state.copiedComponent) {const clone = cloneDeep(state.copiedComponent);clone.id = uuidv4();clone.layerName = clone.layerName + "副本";state.components.push(clone);message.success("已黏贴当前图层", 1);pushHistory(state, {id: uuidv4(),componentId: clone.id,type: "add",data: cloneDeep(clone),});}
})// 删除元素
deleteComponent: setDirtyWrapper((state, id) => {const currentComponent = state.components.find((component) => component.id === id);if (currentComponent) {const currentIndex = state.components.findIndex((component) => component.id === id);state.components = state.components.filter((component) => component.id !== id);pushHistory(state, {id: uuidv4(),componentId: currentComponent.id,type: "delete",data: currentComponent,index: currentIndex,});message.success("删除当前图层成功", 1);}
})//更新元素
updateComponent: setDirtyWrapper((state, { key, value, id, isRoot }: UpdateComponentData) => {const updatedComponent = state.components.find((component) => component.id === (id || state.currentElement));if (updatedComponent) {if (isRoot) {(updatedComponent as any)[key as string] = value;} else {const oldValue = Array.isArray(key)? key.map((key) => updatedComponent.props[key]): updatedComponent.props[key];if (!state.cachedOldValues) {state.cachedOldValues = oldValue;}pushHistoryDebounce(state, { key, value, id });if (Array.isArray(key) && Array.isArray(value)) {key.forEach((keyName, index) => {updatedComponent.props[keyName] = value[index];});} else if (typeof key === "string" && typeof value === "string") {updatedComponent.props[key] = value;}}}}
)

发送完请求后,将isDirty置为false

// store/editor.ts
saveWork(state) {state.isDirty = false;
},

onMounted生命周期里面增加对于的逻辑:

onMounted(() => {timer = setInterval(() => {if (isDirty.value) {saveWork();}}, 1000 * 50);
});
onUnmounted(() => {clearInterval(timer);
});

相关文章:

web架构师编辑器内容-添加自动保存的功能

对于频繁改动的应用&#xff0c;自动保存的功能是一个非常有用的功能&#xff0c;可以避免用户在没有保存的情况下丢失自己保存过的数据。 对于自动保存&#xff0c;一般有两种实现&#xff0c;参考语雀和石墨&#xff1a; 语雀采用的是定时保存的方式&#xff0c;大约在3分半…...

【Redis】关于它为什么快?使用场景?以及使用方式?为何引入多线程?

目录 1.既然redis那么快&#xff0c;为什么不用它做主数据库&#xff0c;只用它做缓存&#xff1f; 2.Redis 一般在什么场合下使用&#xff1f; 3.redis为什么这么快&#xff1f; 4.Redis为什么要引入了多线程&#xff1f; 1.既然redis那么快&#xff0c;为什么不用它做主数据…...

SpringBoot之JWT登录

JWT JSON Web Token&#xff08;JSON Web令牌&#xff09; 是一个开放标准(rfc7519)&#xff0c;它定义了一种紧凑的、自包含的方式&#xff0c;用于在各方之间以JSON对象安全地传输信息。此信息可以验证和信任&#xff0c;因为它是数字签名的。jwt可以使用秘密〈使用HNAC算法…...

【备战蓝桥杯】——循环结构

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-bFHV3Dz5xMe6d3NB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...

【数据分享】1929-2023年全球站点的逐年平均气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01;本次我们为大家带来的就是具体到气象监…...

探索Pyecharts关系图绘制技巧:炫酷效果与创意呈现【第42篇—python:Pyecharts水球图】

文章目录 Pyecharts绘制多种炫酷关系网图引言准备工作代码实战1. 基本关系网图2. 自定义节点样式和边样式3. 关系网图的层级结构4. 添加标签和工具提示5. 动态关系网图6. 高级关系网图 - Les Miserables 示例7. 自定义关系网图布局8. 添加背景图9. 3D 关系网图10. 热力关系网图…...

蓝桥杯-循环节长度

两个整数做除法&#xff0c;有时会产生循环小数&#xff0c;其循环部分称为: 循环节。比如&#xff0c;11/136>0.8461553846153..... 其循环节为[846153] 共有 6 位。下面的方法&#xff0c;可以求出循环节的长度。请仔细阅读代码&#xff0c;并填写划线部分缺少的代码。 注…...

Jython调用openwire库连接activemq转发topic订阅消息到另一个activemq 服务器上 完整代码

以下是一个示例代码&#xff0c;演示如何在Jython中使用OpenWire库连接ActiveMQ&#xff0c;将一个主题&#xff08;topic&#xff09;上的订阅消息转发到另一个ActiveMQ服务器上&#xff1a; from org.apache.activemq import * from org.apache.activemq.transport import *…...

面试经典题---30.串联所有单词的子串

30.串联所有单词的子串 我的解法&#xff1a; 滑动窗口&#xff1a; 解法中用到了两个哈希表map1和map2&#xff0c;分别用于记录words中各个单词的出现频数和当前滑动窗口[left, right)中单词的出现频数&#xff1b;外部for循环i从0到len - 1&#xff0c;内部while循环每次会…...

字符串随机生成工具(开源)-Kimen(奇门)

由于最近笔者在开发数据脱敏相关功能&#xff0c;其中一类脱敏需求为能够按照指定的格式随机生成一个字符串来代替原有信息&#xff0c;数据看起来格式需要与原数据相同&#xff0c;如&#xff1a;电话号码&#xff0c;身份证号以及邮箱等。在网上搜索了下&#xff0c;发现没有…...

UE4 CustomDepthMobile流程小记

原生UE opaque材质中获取CustomDepth/CustomStencil会报错 在其Compile中调用的函数中没有看到报错逻辑 材质节点的逻辑都没有什么问题&#xff0c;所以看一下报错 在HLSLMaterialTranslator::Translate中 修改之后 mobile流程的不透明材质可以直接获取SceneTexture::customd…...

Docker 基础篇

目录 一、Docker 简介 1. Docker 2. Linux 容器 3. 传统虚拟机和容器的对比 4. Docker 的作用 5. Docker 的基本组成&#xff08;Docker 三要素&#xff09; 6. Docker 工作原理 7. Docker 架构 8. Docker 下载 二、Docker 安装 1. CentOS Docker 安装 2. CentOS8 …...

Idea上操作Git回退本地版本,怎么样保留已修改的文件,回退本地版本的四种方式代表什么?

Git的基本概念:Git是一个版本控制系统,用于管理代码的变更历史记录。核心概念包括仓库、分支、提交和合并。 1、可以帮助开发者合并开发的代码 2、如果出现冲突代码的合并,会提示后提交合并代码的开发者,让其解决冲突 3、代码文件版本管理 问题描述 当我们使用git提交代码…...

vue3封装el-pagination分页组件

1、效果如图&#xff1a; 2、分页组件代码&#xff1a; <template><div class"paging"><el-config-provider :locale"zhCn"><el-paginationv-model:current-page"page.currentPage"v-model:page-size"page.pageSize…...

负载均衡下Webshell连接思路及难点

君衍. 一、应用场景二、环境搭建三、思路以及难点1、查看内部结构2、查看webshell3、使用蚁剑进行连接4、难点1 shell文件上传问题5、难点2 命令执行时飘逸6、难点3 大工具上传失败7、难点4 脚本失效 四、解决方式1、关闭对方节点服务器2、基于IP地址判断是否执行3、脚本实现流…...

基于链表实现贪吃蛇游戏

本文中&#xff0c;我们将使用链表和一些Win32 API的知识来实现贪吃蛇小游戏 一、功能 &#xff08;1&#xff09;游戏载入界面 &#xff08;2&#xff09;地图的绘制 &#xff08;3&#xff09;蛇身的移动和变长 &#xff08;4&#xff09;食物的生成 &#xff08;5&…...

Python网络爬虫实战——实验6:Python实现js逆向与加解密

【实验内容】 本实验主要介绍在数据采集过程中对js代码进行分析从而对加密字段进行解密。 【实验目的】 1、理解js逆向工程的概念 2、学会逆向工程中的加解密分析 【实验步骤】 步骤1 理解js逆向工程的概念 步骤2 学会逆向工程中的加解密分析 步骤3 采集广东政府采购网 步…...

【python】使用aiohttp库编写一个简单的异步服务器

1. aiohttp介绍 aiohttp 是一个用于编写异步 HTTP 客户端和服务器的 Python 库。它建立在 Python 的 asyncio 库之上&#xff0c;提供了一种方便的方式来处理异步请求和响应。 官网地址&#xff1a;Welcome to AIOHTTP — aiohttp 3.9.1 documentation 以下是 aiohttp 的一些…...

新手使用代理IP接入代码教程

“实现匿名访问与数据保护在当今互联网高速发展的时代&#xff0c;网络安全和隐私保护成为了越来越重要的议题。代理IP可以隐藏用户的真实IP地址&#xff0c;从而实现匿名访问。为了保护用户的隐私和数据安全&#xff0c;许多网站和应用程序都采用了代理IP技术。” 一、代理IP的…...

JVM问题排查手册

三万字长文&#xff1a;JVM内存问题排查Cookbook 一、Heap快照 # jmap命令保存整个Java堆&#xff08;在你dump的时间不是事故发生点的时候尤其推荐&#xff09; jmap -dump:formatb,fileheap.bin <pid> # jmap命令只保存Java堆中的存活对象, 包含live选项&#xff0c;…...

前端canvas项目实战——简历制作网站(三)——右侧属性栏(线条宽度样式)

目录 前言一、效果展示二、实现步骤1. 实现线条宽度&#xff08;strokeWidth&#xff09;的属性模块2. 实线线条样式&#xff08;strokeDashArray&#xff09;的属性模块3. 意料之外的“联动” 三、Show u the code后记 前言 上一篇博文中&#xff0c;我们初步实现了右侧属性栏…...

字节跳动二面经典题目

前言 语论即为「语兴式论语」&#xff0c;以语录体及对话的形式&#xff0c;沉淀球友实际工作学习中存在的疑难杂症解答&#xff0c;希望能够更好的帮助到球友和粉丝。欢迎关注公众号&#xff1a;语数 本期投稿 本期语数精选来源于球友应对字节跳动二面时候的场景问题 数仓工程…...

微搭低代码从入门到精通01应用介绍

目录 1 学习路线图2 应用介绍3 编辑器介绍总结 低代码的概念于2014年由 Forrester 首次正式提出。其将低代码定义为&#xff1a;能够以“最少的手写代码”和设置快速开发应用、配置和部署业务应用程序。 不同应用厂商的解法不一样&#xff0c;Gartner评估了400多款低代码/无代码…...

论文阅读《thanking frequency fordeepfake detection》

项目链接&#xff1a;https://github.com/yyk-wew/F3Net 这篇论文从频域的角度出发&#xff0c;提出了频域感知模型用于deepfake检测的模型 整体架构图&#xff1a; 1.FAD&#xff1a; 频域感知分解&#xff0c;其实就是利用DCT变换&#xff0c;将空间域转换为频域&#xff…...

ArcgisForJs快速入门

文章目录 0.引言1.前端代码编辑工具2.使用ArcgisForJs创建一个简单应用3.切片地图服务图层4.动态地图服务图层5.地图事件 0.引言 ArcGIS API for JavaScript是一款由Esri公司开发的用于创建WebGIS应用的JavaScript库。它允许开发者通过调用ArcGIS Server的REST API&#xff0c…...

【解决方法】git pull报错ssh: connect to host github.com port 22: Connection timed out

问题 git pull ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository.解决方法 在C:\Users\username.ssh文件夹下新建config文件&#xff0c;填入以下文本&#xff08;如有则直接在文件最后一行新增&#xff09;&am…...

30天精通Nodejs--第三十天:项目实战-物联网应用

目录 引言架构设计编码创建项目数据服务模拟设备消息接收并保存设备数据后端接口项目启动及接口测试项目启动测试源码地址结语引言 在之前的一系列文章中,我们已系统性地探讨了诸多Node.js相关的技术要点与理论背景。随着知识体系的铺垫到位,我们现在步入了实战环节。接下来…...

java 社区资源管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web社区资源管系统是一套完善的java web信息管理系统 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.…...

网络编程套接字(Socket)

为什么需要网络编程??? -丰富的网络资源 每天你在b站上刷着喜欢的up主的视频,实质是通过网络,获取到网络上的一个视频资源 与本地打开文件类似,只是视频文件这个资源来源是网络 所谓的网络编程,其实就是从网络上获取各种数据资源 什么是网络编程?? 网络编程,指的是网络…...

C语言第十一弹---函数(下)

​ ✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 函数 1、嵌套调用和链式访问 1.1、嵌套调用 1.2、链式访问 2、函数的声明和定义 2.1、单个文件 2.2、多个文件 2.3、static 和 extern 2.3.1、static…...