【问题标题】:iframe Undo/Redo for execCommand using insertHTML (contenteditable)使用 insertHTML (contenteditable) 为 execCommand 撤消/重做 iframe
【发布时间】:2019-01-20 17:34:45
【问题描述】:

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

唯一的问题是,如果我执行Command+Z 或在Safari 中按undo,则iframe 将因某种原因无法撤消。它适用于FirefoxChromeEdgeOpera,但出于某种原因,我认为safari 不明白如何undo 它。

除了实现我自己的撤消/重做堆栈之外,还有其他解决方法吗?当用户在 safari 中选择 undo 时,我只想能够摆脱 iframe,并在用户选择 redo 时将其添加回来。请提前帮助和感谢。

编辑:

这是一个 JS fiddle 来演示我在说什么。如果您在除 Safari 之外的任何浏览器中运行它并按撤消,它就可以工作。但不是在 Safari 中。 http://jsfiddle.net/qg41pd3k/9/

【问题讨论】:

  • 对我来说,撤消只是重新打开最后一个关闭的选项卡。
  • execCommand 和 contentEditable 在浏览器之间是出了名的不一致,所以如果可能的话,我建议寻找其他解决方案。但是由于这个问题是关于解决方法的,也许您可​​以在 Safari 中粘贴一些占位符图像?然后稍后将其替换为 iframe?
  • 似乎 Safari 无法撤消 iFrame 的粘贴,但是它们已被插入(尽管奇怪的是,您可以撤消/重做它们的 删除)。当您手动将 iFrame 复制/粘贴到 contenteditable 字段中时,您也无法撤消该操作。

标签: javascript html iframe safari contenteditable


【解决方案1】:

我认为 Safari 并不真正支持它。 检查https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand,无论该命令是否支持/启用,execCommand 方法都会返回真/假。在 Safari 中,它总是返回 false(根据我的测试)。

我认为唯一的解决方法是实现您自己的撤消/重做堆栈。

【讨论】:

  • 这不是真的。那你做错了什么,因为它并不总是返回假。即使您尝试撤消框架,它也不会返回 false。它返回 true 但不执行任何操作。您可能没有在 contenteditable 中运行 document.execCommand。你试过我的小提琴吗?
  • 似乎insertHTML 在您的情况下打破了撤消/重做历史。如果您改用insertText,它将起作用。也许它现在不支持。
  • @Disfigure 实际上,在大多数情况下,撤消/重做与insertHTML 配合得很好。例如,插入 div 而不是 iFrame 可以在 Safari 中顺利运行。
  • @aaplmath 我的意思是,它当然不会与其他标签中断,但对于 OP 用例,iframe 似乎会破坏撤消/重做历史。
【解决方案2】:

我制作了一个小缓存解决方案来模拟相同的行为并使其在 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 仍然存在于 contenteditable 中。无论如何,感谢您提供帮助:)
  • 等等,让我重新表述一下。当我按添加视频然后按撤消时,它不起作用。但是,如果我添加视频,然后将其删除,然后按撤消,它确实会将视频插入到 contenteditable 中。所以,它没有像我所说的那样工作。干杯!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-19
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 2013-03-18
  • 2011-03-10
相关资源
最近更新 更多