web架构师编辑器内容-添加自动保存的功能
对于频繁改动的应用,自动保存的功能是一个非常有用的功能,可以避免用户在没有保存的情况下丢失自己保存过的数据。
对于自动保存,一般有两种实现,参考语雀和石墨:
- 语雀采用的是定时保存的方式,大约在3分半后自动发送一次请求
- 石墨文档采用的是实时保存:对于文本区域,直接输入字符的时候,会发送请求,就是在文本区域onchange的时候,绑定一个事件,有新内容介入的时候发送请求。
这里我们可以采用第一种方法,定时发送请求。采用这种方式之前我们可以进行一个优化:为了避免一股脑的发送请求,比如说如果用户没有做任何操作,到时候还是会发送请求,所以呢,我们要给他添加一个特殊字段isDirty,这个字段可以标记一次数据是否有修改,加入有修改,才进行保存,这里采用的方式和做历史数据功能的方式类似,不会采用对比新旧数据比较耗时的方法,而是触发特定的mutations才会标记字段,比如说addComponent、deleteComponent、updateComponent、updatPage。
// 特殊字段
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架构师编辑器内容-添加自动保存的功能
对于频繁改动的应用,自动保存的功能是一个非常有用的功能,可以避免用户在没有保存的情况下丢失自己保存过的数据。 对于自动保存,一般有两种实现,参考语雀和石墨: 语雀采用的是定时保存的方式,大约在3分半…...
【Redis】关于它为什么快?使用场景?以及使用方式?为何引入多线程?
目录 1.既然redis那么快,为什么不用它做主数据库,只用它做缓存? 2.Redis 一般在什么场合下使用? 3.redis为什么这么快? 4.Redis为什么要引入了多线程? 1.既然redis那么快,为什么不用它做主数据…...
SpringBoot之JWT登录
JWT JSON Web Token(JSON Web令牌) 是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息。此信息可以验证和信任,因为它是数字签名的。jwt可以使用秘密〈使用HNAC算法…...
【备战蓝桥杯】——循环结构
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-bFHV3Dz5xMe6d3NB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...
【数据分享】1929-2023年全球站点的逐年平均气温数据(Shp\Excel\免费获取)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,其中又以气温指标最为常用!说到气温数据,最详细的气温数据是具体到气象监测站点的气温数据!本次我们为大家带来的就是具体到气象监…...
探索Pyecharts关系图绘制技巧:炫酷效果与创意呈现【第42篇—python:Pyecharts水球图】
文章目录 Pyecharts绘制多种炫酷关系网图引言准备工作代码实战1. 基本关系网图2. 自定义节点样式和边样式3. 关系网图的层级结构4. 添加标签和工具提示5. 动态关系网图6. 高级关系网图 - Les Miserables 示例7. 自定义关系网图布局8. 添加背景图9. 3D 关系网图10. 热力关系网图…...
蓝桥杯-循环节长度
两个整数做除法,有时会产生循环小数,其循环部分称为: 循环节。比如,11/136>0.8461553846153..... 其循环节为[846153] 共有 6 位。下面的方法,可以求出循环节的长度。请仔细阅读代码,并填写划线部分缺少的代码。 注…...
Jython调用openwire库连接activemq转发topic订阅消息到另一个activemq 服务器上 完整代码
以下是一个示例代码,演示如何在Jython中使用OpenWire库连接ActiveMQ,将一个主题(topic)上的订阅消息转发到另一个ActiveMQ服务器上: from org.apache.activemq import * from org.apache.activemq.transport import *…...
面试经典题---30.串联所有单词的子串
30.串联所有单词的子串 我的解法: 滑动窗口: 解法中用到了两个哈希表map1和map2,分别用于记录words中各个单词的出现频数和当前滑动窗口[left, right)中单词的出现频数;外部for循环i从0到len - 1,内部while循环每次会…...
字符串随机生成工具(开源)-Kimen(奇门)
由于最近笔者在开发数据脱敏相关功能,其中一类脱敏需求为能够按照指定的格式随机生成一个字符串来代替原有信息,数据看起来格式需要与原数据相同,如:电话号码,身份证号以及邮箱等。在网上搜索了下,发现没有…...
UE4 CustomDepthMobile流程小记
原生UE opaque材质中获取CustomDepth/CustomStencil会报错 在其Compile中调用的函数中没有看到报错逻辑 材质节点的逻辑都没有什么问题,所以看一下报错 在HLSLMaterialTranslator::Translate中 修改之后 mobile流程的不透明材质可以直接获取SceneTexture::customd…...
Docker 基础篇
目录 一、Docker 简介 1. Docker 2. Linux 容器 3. 传统虚拟机和容器的对比 4. Docker 的作用 5. Docker 的基本组成(Docker 三要素) 6. Docker 工作原理 7. Docker 架构 8. Docker 下载 二、Docker 安装 1. CentOS Docker 安装 2. CentOS8 …...
Idea上操作Git回退本地版本,怎么样保留已修改的文件,回退本地版本的四种方式代表什么?
Git的基本概念:Git是一个版本控制系统,用于管理代码的变更历史记录。核心概念包括仓库、分支、提交和合并。 1、可以帮助开发者合并开发的代码 2、如果出现冲突代码的合并,会提示后提交合并代码的开发者,让其解决冲突 3、代码文件版本管理 问题描述 当我们使用git提交代码…...
vue3封装el-pagination分页组件
1、效果如图: 2、分页组件代码: <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、脚本实现流…...
基于链表实现贪吃蛇游戏
本文中,我们将使用链表和一些Win32 API的知识来实现贪吃蛇小游戏 一、功能 (1)游戏载入界面 (2)地图的绘制 (3)蛇身的移动和变长 (4)食物的生成 (5&…...
Python网络爬虫实战——实验6:Python实现js逆向与加解密
【实验内容】 本实验主要介绍在数据采集过程中对js代码进行分析从而对加密字段进行解密。 【实验目的】 1、理解js逆向工程的概念 2、学会逆向工程中的加解密分析 【实验步骤】 步骤1 理解js逆向工程的概念 步骤2 学会逆向工程中的加解密分析 步骤3 采集广东政府采购网 步…...
【python】使用aiohttp库编写一个简单的异步服务器
1. aiohttp介绍 aiohttp 是一个用于编写异步 HTTP 客户端和服务器的 Python 库。它建立在 Python 的 asyncio 库之上,提供了一种方便的方式来处理异步请求和响应。 官网地址:Welcome to AIOHTTP — aiohttp 3.9.1 documentation 以下是 aiohttp 的一些…...
新手使用代理IP接入代码教程
“实现匿名访问与数据保护在当今互联网高速发展的时代,网络安全和隐私保护成为了越来越重要的议题。代理IP可以隐藏用户的真实IP地址,从而实现匿名访问。为了保护用户的隐私和数据安全,许多网站和应用程序都采用了代理IP技术。” 一、代理IP的…...
JVM问题排查手册
三万字长文:JVM内存问题排查Cookbook 一、Heap快照 # jmap命令保存整个Java堆(在你dump的时间不是事故发生点的时候尤其推荐) jmap -dump:formatb,fileheap.bin <pid> # jmap命令只保存Java堆中的存活对象, 包含live选项,…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
