允许 contenteditable 在 dom 修改后撤消
Allowing contenteditable to undo after dom modification
有没有办法使用 javascript 修改 contenteditable 的元素,以便撤消仍然有效?
Hallo 似乎可以做到这一点,请在选择一些文本后尝试单击粗体按钮,我翻阅了它的来源但不知道他们是如何做到的,唯一提到的是 halloreundo
这是一些 gui 工具栏。
我看过 undo.js 但这只是将 html 保存在一个数组中,这确实会限制撤消堆栈的大小,所以我正在寻求本机解决方案,如果可能。
您可以通过 document.execCommand()
而不是直接 DOM 操作来确保编辑操作的撤消能力。
检查这个显示 bold 命令的迷你演示(当然可以撤消):http://jsfiddle.net/qL6Lpy0c/
此代码将保存数组中 contenteditable 的所有更改。您可以通过调用 save_history()
或将此函数附加到任何事件(例如 - 在 keydown
上)来手动保存当前状态。我编写了检查状态相等性的代码,因此如果您在单击事件上绑定 save_history - 如果您单击 10 次而不在编辑器中进行任何更改,它将不会保存 10 个状态。此代码将适用于每个能够 运行 jQuery:
的浏览器
//array to store canvas objects history
canvas_history=[];
s_history=true;
cur_history_index=0;
DEBUG=true;
//store every modification of canvas in history array
function save_history(force){
//if we already used undo button and made modification - delete all forward history
if(cur_history_index<canvas_history.length-1){
canvas_history=canvas_history.slice(0,cur_history_index+1);
cur_history_index++;
jQuery('#text_redo').addClass("disabled");
}
var cur_canvas=JSON.stringify(jQuery(editor).html());
//if current state identical to previous don't save identical states
if(cur_canvas!=canvas_history[cur_history_index] || force==1){
canvas_history.push(cur_canvas);
cur_history_index=canvas_history.length-1;
}
DEBUG && console.log('saved '+canvas_history.length+" "+cur_history_index);
jQuery('#text_undo').removeClass("disabled");
}
function history_undo(){
if(cur_history_index>0)
{
s_history=false;
canv_data=JSON.parse(canvas_history[cur_history_index-1]);
jQuery(editor).html(canv_data);
cur_history_index--;
DEBUG && console.log('undo '+canvas_history.length+" "+cur_history_index);
jQuery('#text_redo').removeClass("disabled");
}
else{
jQuery('#text_undo').addClass("disabled");
}
}
function history_redo(){
if(canvas_history[cur_history_index+1])
{
s_history=false;
canv_data=JSON.parse(canvas_history[cur_history_index+1]);
jQuery(editor).html(canv_data);
cur_history_index++;
DEBUG && console.log('redo '+canvas_history.length+" "+cur_history_index);
jQuery('#text_undo').removeClass("disabled");
}
else{
jQuery('#text_redo').addClass("disabled");
}
}
jQuery('body').keydown(function(e){
save_history();
});
jQuery('#text_undo').click(function(e){
history_undo();
});
jQuery('#text_redo').click(function(e){
history_redo();
});
#text_undo.disabled,#text_redo.disabled{
color: #ccc;
}
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<button id="text_undo" class="disabled">Undo</button><button id="text_redo" class="disabled">Redo</button>
<div id="editor" contenteditable="true">Some editable HTML <b>here</b></div>
</body>
</html>
正如其他人所说,简短的回答是使用 document.execCommand 来保留浏览器的 undo/redo。如果您需要以任何方式以编程方式不可修改地编辑文本(例如支持多行制表符缩进或其他操作文本的快捷方式),您应该使用 document.execCommand('insertHTML') 或 'insertText' 当你设置新的文本状态时。 insertText 将在您编辑时创建新的 div 子项,这可能很麻烦,而 'insertHTML' 不会(但 'insertHTML' 有一些您可能需要解决的 IE 支持问题,在其他地方有详细说明) .
这部分让我陷入了一个巨大的循环,这就是我写一个新答案的原因,因为我没有发现它在任何地方被提及:
您可能还需要捕获 paste 事件并将其转换为 execCommand('insertHTML'),否则您可能会在粘贴后进行任何编程选择更改(如重置光标等)运行 可能会向您抛出一个错误,提示该节点不够长,无法进行新选择,尽管它显然是这样。粘贴后 DOM 以某种方式无法识别 yourDiv.firstNode 的新长度,但它会在您使用 execCommand('insertHTML') 后更新它。可能还有其他解决方案,但这是一个简单的解决方案:
$("#myDiv").on( 'paste', function(e) {
e.preventDefault();
var text = e.originalEvent.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
});
有没有办法使用 javascript 修改 contenteditable 的元素,以便撤消仍然有效?
Hallo 似乎可以做到这一点,请在选择一些文本后尝试单击粗体按钮,我翻阅了它的来源但不知道他们是如何做到的,唯一提到的是 halloreundo
这是一些 gui 工具栏。
我看过 undo.js 但这只是将 html 保存在一个数组中,这确实会限制撤消堆栈的大小,所以我正在寻求本机解决方案,如果可能。
您可以通过 document.execCommand()
而不是直接 DOM 操作来确保编辑操作的撤消能力。
检查这个显示 bold 命令的迷你演示(当然可以撤消):http://jsfiddle.net/qL6Lpy0c/
此代码将保存数组中 contenteditable 的所有更改。您可以通过调用 save_history()
或将此函数附加到任何事件(例如 - 在 keydown
上)来手动保存当前状态。我编写了检查状态相等性的代码,因此如果您在单击事件上绑定 save_history - 如果您单击 10 次而不在编辑器中进行任何更改,它将不会保存 10 个状态。此代码将适用于每个能够 运行 jQuery:
//array to store canvas objects history
canvas_history=[];
s_history=true;
cur_history_index=0;
DEBUG=true;
//store every modification of canvas in history array
function save_history(force){
//if we already used undo button and made modification - delete all forward history
if(cur_history_index<canvas_history.length-1){
canvas_history=canvas_history.slice(0,cur_history_index+1);
cur_history_index++;
jQuery('#text_redo').addClass("disabled");
}
var cur_canvas=JSON.stringify(jQuery(editor).html());
//if current state identical to previous don't save identical states
if(cur_canvas!=canvas_history[cur_history_index] || force==1){
canvas_history.push(cur_canvas);
cur_history_index=canvas_history.length-1;
}
DEBUG && console.log('saved '+canvas_history.length+" "+cur_history_index);
jQuery('#text_undo').removeClass("disabled");
}
function history_undo(){
if(cur_history_index>0)
{
s_history=false;
canv_data=JSON.parse(canvas_history[cur_history_index-1]);
jQuery(editor).html(canv_data);
cur_history_index--;
DEBUG && console.log('undo '+canvas_history.length+" "+cur_history_index);
jQuery('#text_redo').removeClass("disabled");
}
else{
jQuery('#text_undo').addClass("disabled");
}
}
function history_redo(){
if(canvas_history[cur_history_index+1])
{
s_history=false;
canv_data=JSON.parse(canvas_history[cur_history_index+1]);
jQuery(editor).html(canv_data);
cur_history_index++;
DEBUG && console.log('redo '+canvas_history.length+" "+cur_history_index);
jQuery('#text_undo').removeClass("disabled");
}
else{
jQuery('#text_redo').addClass("disabled");
}
}
jQuery('body').keydown(function(e){
save_history();
});
jQuery('#text_undo').click(function(e){
history_undo();
});
jQuery('#text_redo').click(function(e){
history_redo();
});
#text_undo.disabled,#text_redo.disabled{
color: #ccc;
}
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<button id="text_undo" class="disabled">Undo</button><button id="text_redo" class="disabled">Redo</button>
<div id="editor" contenteditable="true">Some editable HTML <b>here</b></div>
</body>
</html>
正如其他人所说,简短的回答是使用 document.execCommand 来保留浏览器的 undo/redo。如果您需要以任何方式以编程方式不可修改地编辑文本(例如支持多行制表符缩进或其他操作文本的快捷方式),您应该使用 document.execCommand('insertHTML') 或 'insertText' 当你设置新的文本状态时。 insertText 将在您编辑时创建新的 div 子项,这可能很麻烦,而 'insertHTML' 不会(但 'insertHTML' 有一些您可能需要解决的 IE 支持问题,在其他地方有详细说明) .
这部分让我陷入了一个巨大的循环,这就是我写一个新答案的原因,因为我没有发现它在任何地方被提及:
您可能还需要捕获 paste 事件并将其转换为 execCommand('insertHTML'),否则您可能会在粘贴后进行任何编程选择更改(如重置光标等)运行 可能会向您抛出一个错误,提示该节点不够长,无法进行新选择,尽管它显然是这样。粘贴后 DOM 以某种方式无法识别 yourDiv.firstNode 的新长度,但它会在您使用 execCommand('insertHTML') 后更新它。可能还有其他解决方案,但这是一个简单的解决方案:
$("#myDiv").on( 'paste', function(e) {
e.preventDefault();
var text = e.originalEvent.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
});