在多输入框的网页应用中,撤销(Undo)和重做(Redo)操作容易变得混乱,因为浏览器默认的撤销栈是基于整个页面的,而非单个输入框。以下是几种解决方案:
为每个输入框维护独立的撤销历史:
class InputHistory {
constructor(inputElement) {
this.input = inputElement;
this.history = [''];
this.position = 0;
inputElement.addEventListener('input', () => {
this.record();
});
}
record() {
// 移除当前位置之后的历史
this.history = this.history.slice(0, this.position + 1);
// 添加新状态
this.history.push(this.input.value);
this.position++;
}
undo() {
if (this.position > 0) {
this.position--;
this.input.value = this.history[this.position];
}
}
redo() {
if (this.position < this.history.length - 1) {
this.position++;
this.input.value = this.history[this.position];
}
}
}
// 为每个输入框创建实例
document.querySelectorAll('input, textarea').forEach(input => {
const history = new InputHistory(input);
// 可以绑定到特定快捷键
});
对于复杂场景,使用contenteditable
div并实现自定义的撤销管理:
document.querySelector('.editable').addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'z') {
e.preventDefault();
// 执行自定义撤销逻辑
}
if (e.ctrlKey && e.key === 'y') {
e.preventDefault();
// 执行自定义重做逻辑
}
});
考虑使用成熟的库来管理撤销重做:
跟踪用户最后操作的输入框,只撤销该输入框的内容:
let lastActiveInput = null;
document.querySelectorAll('input, textarea').forEach(input => {
input.addEventListener('focus', () => {
lastActiveInput = input;
});
});
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'z' && lastActiveInput) {
e.preventDefault();
// 执行lastActiveInput的撤销逻辑
}
});
提供清晰的视觉反馈,显示哪个输入框的撤销重做将被执行:
.input-with-undo-focus {
box-shadow: 0 0 0 2px #4a90e2;
transition: box-shadow 0.3s ease;
}
选择哪种方案取决于您的具体需求、应用复杂度和性能要求。