web应用程序如何检测粘贴事件并检索要粘贴的数据?

我想在文本粘贴到富文本编辑器之前删除HTML内容。

在粘贴后清理文本是有效的,但问题是所有以前的格式都会丢失。例如,我可以在编辑器中编写一个句子并将其加粗,但当我粘贴新文本时,所有格式都会丢失。我只想清除粘贴的文本,并保留以前的任何格式不变。

理想情况下,解决方案应该可以跨所有现代浏览器(例如,MSIE、Gecko、Chrome和Safari)工作。

注意,MSIE有clipboardData.getData(),但我找不到其他浏览器的类似功能。


当前回答

写完这篇文章后,情况发生了变化:现在Firefox在版本22中添加了支持,所有主流浏览器现在都支持在粘贴事件中访问剪贴板数据。请看Nico Burns的回答。

在过去,这在跨浏览器的方式中通常是不可能的。最理想的情况是能够通过paste事件获取粘贴的内容,这在最近的浏览器中是可能的,但在一些较老的浏览器中是不可能的(特别是Firefox < 22)。

当你需要支持旧的浏览器时,你可以做的是相当复杂的和一点hack,可以在Firefox 2+, IE 5.5+和WebKit浏览器(如Safari或Chrome)中工作。TinyMCE和CKEditor的最新版本都使用了这种技术:

Detect a ctrl-v / shift-ins event using a keypress event handler In that handler, save the current user selection, add a textarea element off-screen (say at left -1000px) to the document, turn designMode off and call focus() on the textarea, thus moving the caret and effectively redirecting the paste Set a very brief timer (say 1 millisecond) in the event handler to call another function that stores the textarea value, removes the textarea from the document, turns designMode back on, restores the user selection and pastes the text in.

请注意,这将只适用于键盘粘贴事件,而不是粘贴上下文或编辑菜单。当粘贴事件触发时,将插入符号重定向到文本区域就太晚了(至少在某些浏览器中是这样)。

在不太可能的情况下,您需要支持Firefox 2,请注意您需要将文本区域放置在父文档中,而不是在该浏览器中的所见即所得编辑器iframe的文档中。

其他回答

当用户通过浏览器的用户界面发起“粘贴”操作时,粘贴事件将被触发。

HTML

<div class="source" contenteditable="true">Try copying text from this box...</div>
<div class="target" contenteditable="true">...and pasting it into this one</div>

JavaScript

const target = document.querySelector('div.target');

target.addEventListener('paste', (event) => {
    let paste = (event.clipboardData || window.clipboardData).getData('text');
    paste = paste.toUpperCase();

    const selection = window.getSelection();
    if (!selection.rangeCount) return false;
    selection.deleteFromDocument();
    selection.getRangeAt(0).insertNode(document.createTextNode(paste));

    event.preventDefault();
});

知道更多

写完这篇文章后,情况发生了变化:现在Firefox在版本22中添加了支持,所有主流浏览器现在都支持在粘贴事件中访问剪贴板数据。请看Nico Burns的回答。

在过去,这在跨浏览器的方式中通常是不可能的。最理想的情况是能够通过paste事件获取粘贴的内容,这在最近的浏览器中是可能的,但在一些较老的浏览器中是不可能的(特别是Firefox < 22)。

当你需要支持旧的浏览器时,你可以做的是相当复杂的和一点hack,可以在Firefox 2+, IE 5.5+和WebKit浏览器(如Safari或Chrome)中工作。TinyMCE和CKEditor的最新版本都使用了这种技术:

Detect a ctrl-v / shift-ins event using a keypress event handler In that handler, save the current user selection, add a textarea element off-screen (say at left -1000px) to the document, turn designMode off and call focus() on the textarea, thus moving the caret and effectively redirecting the paste Set a very brief timer (say 1 millisecond) in the event handler to call another function that stores the textarea value, removes the textarea from the document, turns designMode back on, restores the user selection and pastes the text in.

请注意,这将只适用于键盘粘贴事件,而不是粘贴上下文或编辑菜单。当粘贴事件触发时,将插入符号重定向到文本区域就太晚了(至少在某些浏览器中是这样)。

在不太可能的情况下,您需要支持Firefox 2,请注意您需要将文本区域放置在父文档中,而不是在该浏览器中的所见即所得编辑器iframe的文档中。

这个没有使用任何setTimeout()。

我使用这篇很棒的文章来实现跨浏览器支持。

$(document).on("focus", "input[type=text],textarea", function (e) {
    var t = e.target;
    if (!$(t).data("EventListenerSet")) {
        //get length of field before paste
        var keyup = function () {
            $(this).data("lastLength", $(this).val().length);
        };
        $(t).data("lastLength", $(t).val().length);
        //catch paste event
        var paste = function () {
            $(this).data("paste", 1);//Opera 11.11+
        };
        //process modified data, if paste occured
        var func = function () {
            if ($(this).data("paste")) {
                alert(this.value.substr($(this).data("lastLength")));
                $(this).data("paste", 0);
                this.value = this.value.substr(0, $(this).data("lastLength"));
                $(t).data("lastLength", $(t).val().length);
            }
        };
        if (window.addEventListener) {
            t.addEventListener('keyup', keyup, false);
            t.addEventListener('paste', paste, false);
            t.addEventListener('input', func, false);
        }
        else {//IE
            t.attachEvent('onkeyup', function () {
                keyup.call(t);
            });
            t.attachEvent('onpaste', function () {
                paste.call(t);
            });
            t.attachEvent('onpropertychange', function () {
                func.call(t);
            });
        }
        $(t).data("EventListenerSet", 1);
    }
}); 

这段代码扩展了粘贴前的选择句柄: 演示

这个解决方案是替换html标签,简单,跨浏览器;查看这个jsfiddle: http://jsfiddle.net/tomwan/cbp1u2cx/1/,核心代码:

var $plainText = $("#plainText");
var $linkOnly = $("#linkOnly");
var $html = $("#html");

$plainText.on('paste', function (e) {
    window.setTimeout(function () {
        $plainText.html(removeAllTags(replaceStyleAttr($plainText.html())));
    }, 0);
});

$linkOnly.on('paste', function (e) {
    window.setTimeout(function () {
        $linkOnly.html(removeTagsExcludeA(replaceStyleAttr($linkOnly.html())));
    }, 0);
});

function replaceStyleAttr (str) {
    return str.replace(/(<[\w\W]*?)(style)([\w\W]*?>)/g, function (a, b, c, d) {
        return b + 'style_replace' + d;
    });
}

function removeTagsExcludeA (str) {
    return str.replace(/<\/?((?!a)(\w+))\s*[\w\W]*?>/g, '');
}

function removeAllTags (str) {
    return str.replace(/<\/?(\w+)\s*[\w\W]*?>/g, '');
}

注意:你应该在后面做一些关于XSS过滤器的工作,因为这个解决方案不能过滤像'<<>>'这样的字符串

$('#dom').on('paste',function (e){
    setTimeout(function(){
        console.log(e.currentTarget.value);
    },0);
});