代码之家  ›  专栏  ›  技术社区  ›  simonzack

允许contenteditable在dom修改后撤消

  •  16
  • simonzack  · 技术社区  · 10 年前

    是否有一种方法可以使用javascript修改contenteditable的元素,以便撤消操作仍然有效?

    Hallo 似乎可以做到这一点,尝试在选择一些文本后单击粗体按钮,我浏览了它的源代码,不知道他们是如何做到的,唯一提到的是 halloreundo 这是一些gui工具栏。

    我看过 undo.js 但这只是将html保存在一个数组中,这将真正限制撤消堆栈的大小,因此如果可能的话,我正在寻找一个本地解决方案。

    3 回复  |  直到 10 年前
        1
  •  10
  •   techfoobar    10 年前

    您可以通过以下方式确保编辑操作的撤消功能 document.execCommand() 而不是直接DOM操作。

    查看这个显示 大胆的 命令(当然可以取消): http://jsfiddle.net/qL6Lpy0c/

        2
  •  10
  •   A.L    10 年前

    此代码将保存数组中contenteditable的所有更改。您可以通过调用 save_history() 或将此函数附加到任何事件(例如-on 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>
        3
  •  6
  •   gss    7 年前

    正如其他人所说的,简单的答案是使用document.execCommand来保留浏览器的撤消/重做。如果您需要以任何方式以不可行的方式编辑文本(如支持多行制表符缩进或其他操作文本的快捷方式),则在设置新文本状态时应使用document.execCommand(“insertHTML”)或“insertText”。insertText将在您编辑时创建新的div子项,这可能会很麻烦,而“insertHTML”不会(但“insertHTML”有一些IE支持问题,您可能需要解决,请在其他地方详细说明)。

    这部分让我陷入了一个巨大的循环,这就是为什么我要写一个新的答案,因为我没有发现它被提及 在任何地方 :

    您可能还需要抓住 粘贴 事件并将其转换为execCommand('insertHTML'),否则在粘贴之后可能进行的任何编程选择更改(如重置光标等)都有可能会向您抛出错误,指出节点不够长,无法进行新选择,尽管它明显存在。粘贴后,DOM不知何故无法识别Div.firstNode的新长度,但它将在您使用execCommand('insertHTML')后更新它。可能有其他解决方案,但这很简单:

    $("#myDiv").on( 'paste', function(e) {
        e.preventDefault();
        var text = e.originalEvent.clipboardData.getData("text/plain");
        document.execCommand("insertHTML", false, text);
    });
    推荐文章