@aurouscia/au-undo-redo
v1.0.1
Published
一个轻量级的撤销/重做(Undo/Redo)状态管理工具,支持两种存储模式:完整状态存储和增量补丁存储。
Readme
au-undo-redo
一个轻量级的撤销/重做(Undo/Redo)状态管理工具,支持两种存储模式:完整状态存储和增量补丁存储。
安装
npm install @aurouscia/au-undo-redo特性
- 🔄 两种存储模式:完整状态存储(StateStore)和增量补丁存储(PatchStore)
- 🧠 智能去重:自动跳过无变化的状态记录
- 🗂️ 带 ID 数组支持:对带有
id属性的数组进行智能差异计算 - 📦 深拷贝保护:使用
rfdc进行高性能深拷贝,防止外部修改影响历史记录 - ⚡ 轻量快速:使用
fast-deep-equal进行高效的深度比较 - 🎯 TypeScript 支持:完整的类型定义
快速开始
AurStateStore - 完整状态存储
适用于状态对象较小,或需要简单实现的场景。
import { AurStateStore } from '@aurouscia/au-undo-redo'
interface EditorState {
title: string
content: string
settings: { fontSize: number }
}
// 创建 store,容量为 20(默认),可选回调函数
const store = new AurStateStore<EditorState>(20, (canUndo, canRedo) => {
console.log('Can undo:', canUndo, 'Can redo:', canRedo)
})
// 写入状态
store.push({ title: 'Hello', content: 'World', settings: { fontSize: 14 } })
store.push({ title: 'Hello', content: 'World!', settings: { fontSize: 14 } })
// 撤销
const prevState = store.undo()
// 重做
const nextState = store.redo()AurPatchStore - 增量补丁存储
适用于大型状态对象,只存储差异补丁,节省内存。
import { AurPatchStore } from '@aurouscia/au-undo-redo'
interface AppState {
user: { name: string; email: string }
items: Array<{ id: number; text: string; done: boolean }>
settings: { theme: 'light' | 'dark' }
}
const initialState: AppState = {
user: { name: 'John', email: '[email protected]' },
items: [
{ id: 1, text: 'Task 1', done: false },
{ id: 2, text: 'Task 2', done: true }
],
settings: { theme: 'light' }
}
const store = new AurPatchStore<AppState>(initialState, 50)
// 修改普通属性
store.push({
...store.currentState,
user: { name: 'Jane', email: '[email protected]' }
})
// 修改带 id 的数组(智能差异计算)
store.push({
...store.currentState,
items: [
{ id: 1, text: 'Task 1 modified', done: true }, // 修改
{ id: 2, text: 'Task 2', done: true }, // 不变
{ id: 3, text: 'Task 3', done: false } // 新增
]
})
// 撤销会恢复到之前的状态
const prevState = store.undo()API 参考
构造函数
new AurStateStore<T>(historyMaxLength?: number, callBack?: AurAvailabilityCallBack)
new AurPatchStore<T>(initialState: T, historyMaxLength?: number, callBack?: AurAvailabilityCallBack)| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| initialState | T | - | PatchStore 需要初始状态 |
| historyMaxLength | number | 20 | 历史记录最大容量,超出后丢弃最老的记录 |
| callBack | (canUndo: boolean, canRedo: boolean) => void | - | 状态可用性变化时的回调 |
方法
| 方法 | 返回值 | 说明 |
|------|--------|------|
| push(state) | void | 写入新状态 |
| undo() | T \| undefined | 撤销到上一步,返回状态或 undefined(如果没有可撤销的) |
| redo() | T \| undefined | 重做到下一步,返回状态或 undefined(如果没有可重做的) |
属性
| 属性 | 类型 | 说明 |
|------|------|------|
| currentState | T | PatchStore 特有,获取当前状态 |
| history | T[] | 历史记录数组(只读) |
高级特性
带 ID 的数组处理
PatchStore 对带有 id 属性的数组会进行智能差异计算:
- 根据
id匹配数组元素 - 支持新增、删除、修改操作
- 如果数组中有重复
id或部分元素没有id,会自动退化为普通数组处理
interface State {
items: Array<{ id: number; name: string }>
}
// 这种数组会走智能差异计算
const state1 = { items: [{ id: 1, name: 'A' }, { id: 2, name: 'B' }] }
// 这种数组会退化为普通属性处理(因为有重复 id)
const state2 = { items: [{ id: 1, name: 'A' }, { id: 1, name: 'B' }] }无变化自动跳过
两个 Store 都会自动检测状态是否真正发生变化:
- 引用相同(
===)的对象不会记录 - 深度相等(内容相同)的对象不会记录
const store = new AurStateStore<Data>(20)
const data = { x: 1 }
store.push(data) // 记录
store.push(data) // 不记录(引用相同)
store.push({ x: 1 }) // 不记录(深度相等)
store.push({ x: 2 }) // 记录(有变化)选择合适的 Store
| 场景 | 推荐 Store |
|------|-----------|
| 状态对象较小(< 100KB) | AurStateStore |
| 状态对象较大或历史记录多 | AurPatchStore |
| 需要频繁保存状态 | AurPatchStore |
| 简单的使用场景 | AurStateStore |
| 带 ID 的数组需要精确 diff | AurPatchStore |
技术细节
- 深拷贝:使用
rfdc(Really Fast Deep Clone)进行高性能深拷贝 - 深度比较:使用
fast-deep-equal进行高效的深度相等性检查 - 内存管理:历史记录超出容量后自动丢弃最老的记录
