使用insertHTML(contenteditable)实现iframe的撤销/重做功能的execCommand

9

目前我正在开发一个小按钮,要求用户输入视频链接,然后将该链接转换为 iframe,并使用 document.execCommand("insertHTML", false, "<iframe width='350' height='551' src='<video_link_entered_by_user>'></iframe>") 将其插入到可编辑区域中。这个功能很好用,视频可以嵌入到 contenteditable 中。

唯一的问题是,如果我在 Safari 中按下 Command+Z 或者点击 undoiframe 不会撤销。它在 FirefoxChromeEdgeOpera 中都能正常工作,但是似乎 Safari 不知道如何撤销它。

除了实现自己的撤销/重做堆栈之外,是否有任何解决方法?我只想在用户选择撤销时能够清除 iframe,并在用户选择重做时重新添加它。请帮忙,谢谢!

编辑:

这里有一个 JSFiddle,演示了我的问题。如果在 Safari 以外的浏览器中运行此代码并按下撤销,则可以看到效果。但在 Safari 中无法正常工作。 http://jsfiddle.net/qg41pd3k/9/


对我来说,撤销只是重新打开最后关闭的标签页。 - LeZuse
execCommand和contentEditable在不同的浏览器中表现不一致,所以如果可能的话,我建议探索其他解决方案。但既然这个问题是关于解决方法的,也许你可以在Safari中粘贴一些占位符图片?然后稍后再用iframe替换它? - LeZuse
似乎Safari无法撤消iFrames的粘贴,无论它们是如何插入的(尽管奇怪的是,您可以撤消/重做它们的删除)。当您手动将iFrame复制/粘贴到“contenteditable”字段中时,也无法撤消该操作。 - aaplmath
2个回答

2

这不是真的。那么你肯定做错了什么,因为它并不总是返回false。即使你尝试撤销框架,它也不会返回false。它会返回true但不会执行任何操作。你可能没有在contenteditable中运行document.execCommand。你试过我的fiddle了吗? - Yang K
在你的情况下,似乎“insertHTML”会破坏撤销/重做历史记录。 如果改用“insertText”,它将正常工作。也许现在只是不支持。 - Disfigure
@Disfigure 实际上,在大多数情况下,使用 insertHTML 进行撤销/重做功能是正常工作的。例如,插入一个 div 而不是 iFrame,在 Safari 中可以毫无问题地工作。 - aaplmath
@aaplmath,这就是我的意思。当然它不会破坏其他标签,但对于OP使用情况来说,iframe似乎会破坏撤销/重做历史记录。 - Disfigure

0

我做了一个小的缓存解决方案来模拟相同的行为,并使其在Safari上运行。

  • 添加视频按钮
  • 撤销/重做按钮
  • ctrl+Zcmd+Z
  • ctrl+Ycmd+Y

希望这段代码示例能对您有所帮助。

可以添加一些优化,例如防抖函数和增加缓存限制。

$(document).ready(function () {
    var $document = $(document);
    var $editor = $('#editor');
    var $redo = $('#redo');
    var $undo = $('#undo');
    var $addVideo = $('#add-video');

    var CACHE_LIMIT = 1000;
    var cache = [];
    var position = 0;
    var zKeyCode = 90;
    var yKeyCode = 89;
    
    var editorKeydownEventHandler = function (event) {
        var ctrl = (event.ctrlKey || event.metaKey);

        if (ctrl && event.keyCode === zKeyCode) {
            event.preventDefault();
            event.stopPropagation();
            undo();
        }
        else if (ctrl && event.keyCode === yKeyCode) {
            event.preventDefault();
            event.stopPropagation();
            redo();
        }
    };

    var editorInputEventHandler = function (event) {
        if(cache.length >= CACHE_LIMIT) {
            cache = cache.slice(1);
        }

        cache.push($editor.html());
        position++;
    };

    var redoClickEventHandler = function (event) {
        redo();
    };


    var undoClickEventHandler = function (event) {
        undo();
    };

    var addVideoClickEventHandler = function (event) {
        addVideo();
    };

    var redo = () => {
        if(cache[position + 1]) {
            position++;
            $editor.html(cache[position]);
        }
    };

    var undo = () => {
        console.log('undo');
        if(cache[position - 1]) {
            position--;
            $editor.html(cache[position]);
        }
    };

    var addVideo = function () {
        document.execCommand("insertHTML", false, "<iframe src='https://www.youtube.com/embed/9P6rdqiybaw' height='100' width='100'></iframe>")
    };

    $document.bind('keydown', editorKeydownEventHandler);
    $editor.bind('input', editorInputEventHandler);
    $redo.click(redoClickEventHandler);
    $undo.click(undoClickEventHandler);
    $addVideo.click(addVideoClickEventHandler);
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
     <div id="editor" contenteditable="true">
         Lorem ipsum dolor sit amet, consectetur adipisicing elit. At culpa exercitationem itaque maxime porro reiciendis repudiandae veniam vero! Alias at doloremque exercitationem fugiat ipsum natus nihil numquam provident sint, voluptatibus.
     </div>
     <button id="add-video">add video</button>
     <button id="undo">undo</button>
     <button id="redo">redo</button>
     <script
             src="https://code.jquery.com/jquery-3.3.1.min.js"
             crossorigin="anonymous"></script>
     <script src="index.js"></script>
</body>
</html>


抱歉,伙计,这个不起作用。当我尝试撤销/重做时,iframe仍然存在于可编辑内容中。无论如何,感谢你的帮助 :) - Yang K
等等,让我重新表达一下。当我点击添加视频,然后再点击撤销时,它不起作用。但是,如果我添加视频,然后将其删除,然后再点击撤销,它会将视频重新插入到可编辑内容中。所以,我想说它没有按预期工作。干杯! - Yang K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接