愈来愈多的前端用于编辑器类工具的开发,常见的如富文本编辑器、H5页面生成器、低代码平台etc... 对于这类编辑器的工具除去ctrl+c ctrl+v外 ,通常还须要有ctrl+z ctrl+y的功能。如何设计一个用户历史记录的队列才能更好的实现用户编辑的前进后退前端
就是说假设用户有以下操做数组
咱们是记录为浏览器
['a', 'ab' , 'abc']
markdown
仍是app
[ {type: 'add" value: 'a'}, {type: 'add" value: 'b'}, {type: 'add" value: 'c'}, ]
编辑器
对于这个问题要看具体的项目类型,如单一类型的操做,数据量不大,能够直接保存每一步的操做时的所有数据状态,如简单的文本编辑器,而对于操做复杂,数据量大咱们选用方式二。工具
对于方式二,咱们我看根据项目的操做自定义操做类型,如咱们是一个H5编辑器,咱们能够分类为:ui
在用户后退或前进时,咱们能够根据上一步修改的数据,进行对应的恢复,或者逆向修改;this
肯定了记录的内容,如何建立一个历史记录? 什么时间添加呢? 当前的状态又如何指向呢?url
首先咱们建立一个历史记录类,用一个数组保存数据,用一个变量为指针,指向用户当前的最新操做
export default class History {
constructor() {
this.historyStore = []
this.historyIndex = -1
this.max = 100;//最大记录数目
}
}
复制代码
假设用户有以下操做:
step | action |
---|---|
1 | a |
2 | b |
3 | c |
4 | d |
5 | back |
6 | back |
7 | e |
8 | f |
1)指针默认指向用户当前的最新操做
2)用户后退,指针后退
3)后退后再添加记录,删除当前指针后面的元素,再添加新的记录
代码实现为
// 新增记录
addItem(d) {
// 撤销后从新添加记录 删除撤销的记录
if(this.historyIndex != this.historyStore.length - 1){
let dif = this.historyStore.length - this.historyIndex - 1
this.historyStore.splice(this.historyIndex, dif)
}
// 新增记录
this.historyStore.push(d)
this.historyIndex ++ ;
// 超出
if(this.historyIndex.length > this.max){
this.historyStore.shift()
this.historyIndex --
}
}
// 后退
back() {
if(this.historyStore.length == 0 || this.historyIndex < 0) return;
this.historyIndex --
}
// 前进
go() {
if(this.historyStore.length == 0 || this.historyIndex >= this.historyStore.length) return;
this.historyIndex ++
}
复制代码
对于用户的操做,咱们能够再数据更新前添加未更新前数据到记录,也能够在更新后记录后新后的数据
如用户有如下操做
step | action |
---|---|
1 | a |
2 | b |
3 | c |
4 | back |
第一次后退时,需记录当前最后一步更新后的数据,以保证能前进到最新数据
以确保后退到开始时候,有最初数据
这样每次咱们后退时还须判断更新的记录,肯定恢复的数据,
//按键摁下记录各个特殊键
let ctrlDown = false;
window.addEventListener('keydown', function (e) {
if (['Control', 'Meta'].includes(e.key)) {
ctrlDown = true;
}
if(ctrlDown && e.key == 'Z') //后退。。。
if(ctrlDown && e.key == 'Y') //前进。。。
})
// 松开按键
window.addEventListener('keyup', function (e) {
if (['Control', 'Meta'].includes(e.key)) {
ctrlDown = false;
}
})
// 浏览器脱离焦点,释放
window.onblur = function() {
ctrlDown = false;
};
复制代码