目录
Undo、Redo用到了simpleReactive响应式,事件系统,和主类board.js、组件History相互关联,复杂的逻辑,清晰的实现,是整个项目的典范。
History类的实现
History类中有一个数组stack,和一个指向当前历史的指针cur,canUndo、canRedo方法通过当前指针返回true/false。
class History { constructor(options) { options = options || {}; this.maxLength = options.maxLength || 30; this.callback = options.callback || function callback() {}; this.stack = []; this.cur = -1; } first() { return this.stack[0]; } current() { return this.stack[this.cur]; } clear() { this.stack = []; this.cur = -1; } save(obj) { // undo 过程中,执行保存,则删除后面的,形成新的链 if (this.cur < this.stack.length - 1) { this.stack.splice(this.cur + 1); } this.stack.push(obj); this.cur++; if (this.stack.length > this.maxLength) { this.stack.shift(); this.cur--; } this.callback('save', obj); } undo() { this.cur--; this.callback('undo', this.stack[this.cur]); return this.stack[this.cur]; } redo() { this.cur++; this.callback('redo', this.stack[this.cur]); return this.stack[this.cur]; } // 最少要有两个历史记录,才能回退 canUndo = function () { return this.cur > 0; } canRedo = function () { return this.cur < this.stack.length - 1; } } export default History;
UndoBtn的实现
绑定了事件监听board:history,每次点击undo、redo按钮,每次绘图结束,都会触发事件board:history,进而更新UI。通过History类的的canUndo方法更新响应式变量,进而更新UI。
可以说,只要把History类的的canUndo方法逻辑写好,就不会出现错误,可预见性大幅度提高。虽然步骤繁琐了,代码增加了,但是对大脑的负担大大下降。
this.board.ev.bind('board:history', this.updateUIData());
import Controller from './controller'; import { simpleReactive, effect } from '../util/simpleReactive'; class UndoBtn extends Controller { constructor(board) { super(board); } init() { this.name = this.constructor.name; this.btn = this.board.template.undoBtn; this.ret = simpleReactive({ active: false, }); this.btn.addEventListener('click', () => { if (!this.ret.active) return; // undo() 会触发 'board:history' 事件,回调函数在 Board 类中配置了 this.board._setImage(this.board.history.undo()); }); this.reactiveUI(); this.board.ev.bind('board:history', this.updateUIData()); } onBoardReset() { return () => { console.log(`触发 board:reset -> target: ${this.name}`); this.updateUIData()(); } } updateUIData() { return () => { if (this.board.history.canUndo()) { this.ret.active = true; } else { this.ret.active = false; } } } reactiveUI() { effect(() => { if (this.ret.active) { if (!this.btn.classList.contains('active')) { this.btn.classList.add('active'); } } else { if (this.btn.classList.contains('active')) { this.btn.classList.remove('active'); } } }); } } export default UndoBtn;
反馈:您觉得本站怎么样?(此评价不会公开,也不会对博主产生任何实际利益。)
- 非常优秀
- 可以
- 一般
- 垃圾
- 超级恶心