功能點描述
大家應該都使用過瀏覽器的後退和前進功能,它就是我們今天的主題:撤銷和回退。其實不光是在瀏覽器裡面,在眾多的工具軟體內也都有類似的功能,遠的不說,例如:vscode、ppt。
實現思路
在說實現思路之前,我先上一張圖:
眼尖的同學可能已經看到了 Stack ,是的,你想的沒錯,其實撤銷和回退功能就是對 Stack 的使用場景之一。
首先我們需要兩個 Stack(可撤銷棧和可回退棧)
為了更直觀的展示,我用點選小球代替了對網站的訪問。
A 為紅色小球;B 為綠色小球;C 為藍色小球
- 當點選 A 之後再點選 B,把 A 和 B 新增到‘可撤銷棧’(等同於先訪問了 A 網站,後又訪問了 B 網站),當前展示的為 B
- 當執行撤銷功能時讓‘可撤銷棧’出棧並且把出棧的 B 新增到‘可回退棧’內,當前展示的為 A
3. 當執行回退功能時讓‘可回退棧’出棧並且把出棧的 B 新增到‘可撤銷棧’內,當前展示的為 B
4. 當我們訪問了 A 和 B 之後,這時候撤銷了 B ,回到了 A ,並且又點選了 C ,這時候我們需要清空‘可回退棧’,並且把 C 新增到‘可撤銷棧’
code
先實現一個特殊的棧
為什麼叫它是特殊的棧呢,因為傳統的棧是沒有 #shift() 功能的。那這裡為什麼需要有這個函式呢,請帶著問題繼續往下看。
這裡偷懶直接使用了 Array 的內建函式,傳統上來講的話不應該使用 – -#
function createStack() {
var list = [];
return {
/**
* 入棧
* @param {*} data
*/
push(data) {
list.push(data);
},
/**
* 出棧
*/
pop() {
return list.pop();
},
size() {
return list.length;
},
empty() {
return list.length === 0;
},
clear() {
list = [];
},
//刪除頭結點(棧底)
shift() {
list.shift();
},
peek() {
return list[list.length - 1];
},
getList() {
return list;
}
}
}
複製程式碼
record物件
function createRecord() {
let undoStack = createStack();
let rollbackStack = createStack();
const MAX_LIMIT = 6;//最大限制點
return {
//獲取可撤銷棧 棧頂的資料
//用於展示
getTopValue() {
return undoStack.peek();
},
//新增記錄
//把資料直接新增到可撤銷棧內
//並且清空可回退棧
addRecord(data) {
//當可撤銷棧的大小大於最大的限制的話
//那麼需要刪除頭結點
if (undoStack.size() >= MAX_LIMIT) {
undoStack.shift();
}
undoStack.push(data);
rollbackStack.clear();
},
//撤銷
//檢測可撤銷棧是否為空,為空的話什麼也不做
//不然把可撤銷棧出棧的資料新增到可回退棧內
undoRecord() {
if (undoStack.empty()) return;
const data = undoStack.pop();
rollbackStack.push(data);
},
//回退
//檢測可回退棧是否為空,為空的話什麼也不做
//把可回退棧出棧的資料新增到可撤銷棧內
rollbackRecord() {
if (rollbackStack.empty()) return;
const data = rollbackStack.pop();
undoStack.push(data);
},
getUndoStack() {
return undoStack.getList();
},
getrollbackStack() {
return rollbackStack.getList();
}
}
}
複製程式碼
我們在使用 vscode 寫程式碼的時候有沒有發現撤銷到一定的數量時,就撤銷不回去了。是的,這個邏輯就是在 #addRecord() 內處理的。當‘可撤銷棧’的大小大於限制數時,那麼需要拋棄掉最初的資料,也就是刪除頭結點。這也是說明為什麼我們實現的 Stack 內有 #shift() 功能。
總結
以上的邏輯我也是在公司專案邏輯中抽離出來的,因為接手的好幾個專案都要實現此功能。當然了公司專案中我又加了 Command 模式來搭配使用,如果大家有興趣的話,後續我可以在更新如何搭配 Command 模式使用。最後想說的是,資料結構和演算法誰學誰知道,真香。
連結
如果此教程對你有幫助的話,請賞賜一個小星星 -_-!