愈來愈多的前端用於編輯器類工具的開發,常見的如富文本編輯器、H5頁面生成器、低代碼平臺etc... 對於這類編輯器的工具除去ctrl+c ctrl+v外 ,通常還須要有ctrl+z ctrl+y的功能。如何設計一個用戶歷史記錄的隊列才能更好的實現用戶編輯的前進後退前端
就是說假設用戶有以下操做數組
咱們是記錄爲瀏覽器
['a', 'ab' , 'abc']
編輯器
仍是工具
[ {type: 'add" value: 'a'}, {type: 'add" value: 'b'}, {type: 'add" value: 'c'}, ]
this
對於這個問題要看具體的項目類型,如單一類型的操做,數據量不大,能夠直接保存每一步的操做時的所有數據狀態,如簡單的文本編輯器,而對於操做複雜,數據量大咱們選用方式二。spa
對於方式二,咱們我看根據項目的操做自定義操做類型,如咱們是一個H5編輯器,咱們能夠分類爲:設計
在用戶後退或前進時,咱們能夠根據上一步修改的數據,進行對應的恢復,或者逆向修改;指針
肯定了記錄的內容,如何建立一個歷史記錄? 什麼時間添加呢? 當前的狀態又如何指向呢?code
首先咱們建立一個歷史記錄類,用一個數組保存數據,用一個變量爲指針,指向用戶當前的最新操做
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; };