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

Goo*_*bot 92 javascript html5 javascript-events execcommand

我有一个基本编辑器,基于execCommand这里介绍的示例.在该区execCommand域内粘贴文本有三种方法:

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

我想只允许粘贴纯文本,不带任何HTML标记.如何强制前两个操作粘贴纯文本?

可能的解决方案:我能想到的方法是在粘贴之前为(Ctrl+ V)设置用于keyup事件的监听器并剥离HTML标签.

  1. 这是最好的解决方案吗?
  2. 是否可以防止粘贴中出现任何HTML标记?
  3. 如何将侦听器添加到右键单击 - >粘贴?

pim*_*vdb 221

它将截取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);
});
Run Code Online (Sandbox Code Playgroud)

  • `var text =(event.originalEvent || event).clipboardData.getData('text/plain');`提供更多的跨浏览器兼容性 (14认同)
  • 这打破了撤消功能.(按Ctrl + Z) (9认同)
  • 我发现`insertHTML`和`insertText`在IE11中不起作用,但是`document.execCommand('paste',false,text);`工作正常.虽然那时似乎不适用于其他浏览器> _>. (5认同)
  • @Ali:我错过了一些明显的东西.如果`text`包含HTML(例如,如果您将HTML代码复制为纯文本),那么它实际上会将其粘贴为HTML.这是一个解决方案,但它不是很漂亮:http://jsfiddle.net/HBEzc/3/. (4认同)
  • `execCommand` 现已[过时](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) (3认同)
  • 很好的解决方案,但这与默认行为有所不同。如果用户复制了<div> </ div>之类的内容,则该内容将作为contenteditable元素的子元素添加。我像这样修复它:`document.execCommand(“ insertText”,false,text);` (2认同)
  • 使用`return false;`代替`e.preventDefault();`来保持`undo`(Ctrl + Z)工作 (2认同)

Jam*_*ker 34

我无法在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);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • @Fanky看看你是否可以在这里重新创建它:https://jsfiddle.net/v2qbp829/. (2认同)
  • 现在看来我遇到的问题是由于脚本是从一个本身由脚本加载的文件中调用脚本的.在FF 47.0.1中我不能粘贴到textarea或者你的小提琴中输入(可以用chrome做),但可以粘贴到div contenteditable,这对我来说很关键.谢谢! (2认同)

Adr*_*ves 20

作为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);
    }   
});
Run Code Online (Sandbox Code Playgroud)

  • 我不认为你可以编写`document.selection.createRange().pasteHTML(内容)`...刚刚在IE11上测试过,它不能像那样工作. (6认同)
  • 我喜欢短路`content`变量赋值.我发现使用`getData('Text')`可以跨浏览器工作,所以你可以像这样进行一次赋值:`var content =((e.originalEvent || e).clipboardData || window.clipboardData) .getData('Text');`那么你只需要使用逻辑来进行跨浏览器粘贴/插入命令. (5认同)
  • `document.execCommand('insertText',false,content)`从IE11和Edge开始不起作用.此外,最新版本的Chrome现在支持`document.execCommand('paste',false,content)`,这更简单.他们可能会弃用`insertText`. (3认同)

web*_*mer 17

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

这是我的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);
}
Run Code Online (Sandbox Code Playgroud)

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


更新19.11.2014: 另一个SO帖子

  • 这在IE11,Chrome和Firefox中完美运行!http://jsfiddle.net/28GyU/ (4认同)
  • 我想你指的是这篇文章:http://stackoverflow.com/questions/21257688/paste-rich-text-into-content-editable-div-and-only-keep-bold-and-italics-formatt (2认同)

dpr*_*dpr 9

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

  • 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);
    }
};
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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