在 execCommand 中“粘贴为纯文本”的 Javascript 技巧

IT技术 javascript html dom-events execcommand
2021-02-09 22:41:58

我有一个基于execCommand这里介绍的示例的基本编辑器可通过三种方式在execCommand区域内粘贴文本

  • Ctrl+V
  • 右键单击 -> 粘贴
  • 右键单击 -> 粘贴为纯文本

我想只允许粘贴没有任何 HTML 标记的纯文本。如何强制前两个操作粘贴纯文本?

可能的解决方案:我能想到的方法是为 ( Ctrl+ V) 的keyup 事件设置侦听器并在粘贴之前去除 HTML 标签。

  1. 这是最好的解决方案吗?
  2. 避免粘贴任何 HTML 标记是否防弹?
  3. 如何将侦听器添加到右键单击-> 粘贴?
6个回答

它将拦截paste事件,取消paste,并手动插入剪贴板的文本表示:
http : //jsfiddle.net/HBEzc/这应该是最可靠的:

  • 它捕获各种粘贴(Ctrl+ V,上下文菜单等)
  • 它允许您直接以文本形式获取剪贴板数据,因此您不必进行丑陋的黑客攻击来替换 HTML。

不过,我不确定是否支持跨浏览器。

editor.addEventListener("paste", function(e) {
    // cancel paste
    e.preventDefault();

    // get text representation of clipboard
    var text = (e.originalEvent || e).clipboardData.getData('text/plain');

    // insert text manually
    document.execCommand("insertHTML", false, text);
});
我发现insertHTML并且insertText在 IE11 中不起作用,但是document.execCommand('paste', false, text);效果很好。尽管这在其他浏览器中似乎不起作用>_>。
2021-03-13 22:41:58
这破坏了撤消功能。(Ctrl+Z)
2021-03-21 22:41:58
很好的解决方案,但这与默认行为不同。如果用户复制类似<div></div>内容的内容将被添加为 contenteditable 元素的子元素。我是这样修复的:document.execCommand("insertText", false, text);
2021-03-23 22:41:58
var text = (event.originalEvent || event).clipboardData.getData('text/plain'); 提供更多的跨浏览器兼容性
2021-03-28 22:41:58
@Ali:我错过了一些明显的东西。如果text包含 HTML(例如,如果您将 HTML 代码复制为纯文本),那么它实际上会将其粘贴为 HTML。这是一个解决方案,但它不是很漂亮:jsfiddle.net/HBEzc/3
2021-04-11 22:41:58

我无法在这里获得可接受的答案以在 IE 中工作,所以我进行了一些侦察并得出了这个适用于 IE11 以及最新版本的 Chrome 和 Firefox 的答案。

$('[contenteditable]').on('paste', function(e) {
    e.preventDefault();
    var text = '';
    if (e.clipboardData || e.originalEvent.clipboardData) {
      text = (e.originalEvent || e).clipboardData.getData('text/plain');
    } else if (window.clipboardData) {
      text = window.clipboardData.getData('Text');
    }
    if (document.queryCommandSupported('insertText')) {
      document.execCommand('insertText', false, text);
    } else {
      document.execCommand('paste', false, text);
    }
});
现在看来,我遇到的问题是由于从本身由脚本加载的文件中调用您的脚本。我无法在 FF 47.0.1 中粘贴到 textarea 或 input 中(可以在 chrome 中执行),但可以粘贴到 div contenteditable 中,这对我来说很关键。谢谢!
2021-03-17 22:41:58
谢谢,我正在为同样的问题苦苦挣扎...... insertText 既不适用于 IE11 也不适用于最新的 FF :)
2021-03-28 22:41:58
在某些情况下,是否有可能在 Firefox 和 Chrome 中将文本粘贴两次?对我来说..
2021-04-04 22:41:58
@Fanky 看看你是否可以在这里重新创建它:jsfiddle.net/v2qbp829
2021-04-05 22:41:58
@Fanky 我在创建它时没有遇到这个问题,但是我不再在创建此代码的地方工作,所以我无法告诉您它是否仍然有效!你能描述一下它是如何粘贴两次的吗?
2021-04-09 22:41:58

作为 pimvdb 的紧密解决方案。但它适用于 FF、Chrome 和 IE 9:

editor.addEventListener("paste", function(e) {
    e.preventDefault();

    if (e.clipboardData) {
        content = (e.originalEvent || e).clipboardData.getData('text/plain');

        document.execCommand('insertText', false, content);
    }
    else if (window.clipboardData) {
        content = window.clipboardData.getData('Text');

        document.selection.createRange().pasteHTML(content);
    }   
});
document.execCommand('insertText', false, content)从 IE11 和 Edge 开始不起作用。此外,最新版本的 Chrome 现在支持document.execCommand('paste', false, content),这更简单。他们可能会弃用insertText
2021-03-20 22:41:58
我喜欢短路content变量赋值。我发现使用getData('Text')跨浏览器工作,所以你可以像这样进行一次分配:var content = ((e.originalEvent || e).clipboardData || window.clipboardData).getData('Text');然后你只需要使用跨浏览器粘贴/插入命令的逻辑。
2021-03-26 22:41:58
我不认为你可以写document.selection.createRange().pasteHTML(content)……只是在 IE11 上测试过,它不能那样工作。
2021-03-31 22:41:58

当然,这个问题已经回答了,而且这个话题很老了,但我想提供我的解决方案,因为它很简单:

这是在我的 contenteditable-div 上的粘贴事件中。

var text = '';
var that = $(this);

if (e.clipboardData)
    text = e.clipboardData.getData('text/plain');
else if (window.clipboardData)
    text = window.clipboardData.getData('Text');
else if (e.originalEvent.clipboardData)
    text = $('<div></div>').text(e.originalEvent.clipboardData.getData('text'));

if (document.queryCommandSupported('insertText')) {
    document.execCommand('insertHTML', false, $(text).html());
    return false;
}
else { // IE > 7
    that.find('*').each(function () {
         $(this).addClass('within');
    });

    setTimeout(function () {
          // nochmal alle durchlaufen
          that.find('*').each(function () {
               // wenn das element keine klasse 'within' hat, dann unwrap
               // http://api.jquery.com/unwrap/
               $(this).not('.within').contents().unwrap();
          });
    }, 1);
}

其他部分来自另一个我找不到的SO帖子......


2014 年 11 月 19 日更新: 另一个 SO-post

在 Safari 中似乎对我不起作用。也许有什么不对
2021-03-23 22:41:58
我想你指的是这篇文章:stackoverflow.com/questions/21257688/...
2021-03-27 22:41:58

发布的答案似乎都没有真正适用于跨浏览器,或者解决方案过于复杂:

  • insertTextIE 不支持该命令
  • paste在 IE11 中使用该命令导致堆栈溢出错误

对我有用的(IE11、Edge、Chrome 和 FF)如下:

$("div[contenteditable=true]").off('paste').on('paste', function(e) {
    e.preventDefault();
    var text = e.originalEvent.clipboardData ? e.originalEvent.clipboardData.getData('text/plain') : window.clipboardData.getData('Text');
    _insertText(text);
});

function _insertText(text) { 
    // use insertText command if supported
    if (document.queryCommandSupported('insertText')) {
        document.execCommand('insertText', false, text);
    }
    // or insert the text content at the caret's current position
    // replacing eventually selected content
    else {
        var range = document.getSelection().getRangeAt(0);
        range.deleteContents();
        var textNode = document.createTextNode(text);
        range.insertNode(textNode);
        range.selectNodeContents(textNode);
        range.collapse(false);

        var selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
    }
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<textarea name="t1"></textarea>
<div style="border: 1px solid;" contenteditable="true">Edit me!</div>
<input />
</body>

请注意,自定义粘贴处理程序只需要/为contenteditable节点工作由于字段textarea和普通input字段根本不支持粘贴 HTML 内容,因此此处无需执行任何操作。

我必须.originalEvent在事件处理程序(第 3 行)中摆脱它才能使其工作。因此,整条生产线是这样的:const text = ev.clipboardData ? ev.clipboardData.getData('text/plain') : window.clipboardData.getData('Text');适用于最新的 Chrome、Safari、Firefox。
2021-03-21 22:41:58
需要替换var text = e.originalEvent.clipboardData ? e.originalEvent.clipboardData.getData('text/plain') : window.clipboardData.getData('Text');var text = (e.originalEvent || e).clipboardData.getData('text/plain');
2021-04-07 22:41:58