JavaScript在粘贴事件中获取剪贴板数据(跨浏览器)

JavaScript get clipboard data on paste event (Cross browser)

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

在将文本粘贴到RTF编辑器中之前,我想删除HTML内容。

之后粘贴后清除文本是可行的,但是问题是所有以前的格式都丢失了。 例如,我可以在编辑器中写一个句子并将其设置为粗体,但是当我粘贴新文本时,所有格式都将丢失。 我只想清除粘贴的文本,并保留所有以前的格式。

理想情况下,该解决方案应可在所有现代浏览器(例如MSIE,Gecko,Chrome和Safari)上运行。

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


解决方案1(仅纯文本,需要Firefox 22+)

适用于IE6 +,FF 22 +,Chrome,Safari,Edge
(仅在IE9 +中经过测试,但应在较低版本中使用)

如果需要粘贴<= 22的HTML或Firefox的支持,请参阅解决方案#2。

的HTML

1
Paste

的JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function handlePaste (e) {
    var clipboardData, pastedData;

    // Stop data actually being pasted into div
    e.stopPropagation();
    e.preventDefault();

    // Get pasted data via clipboard API
    clipboardData = e.clipboardData || window.clipboardData;
    pastedData = clipboardData.getData('Text');

    // Do whatever with pasteddata
    alert(pastedData);
}

document.getElementById('editableDiv').addEventListener('paste', handlePaste);

JSFiddle:https://jsfiddle.net/swL8ftLs/12/

请注意,此解决方案为getData函数使用参数'Text',这是非标准的。但是,在撰写本文时,它可在所有浏览器中使用。

解决方案#2(HTML且适用于Firefox <= 22)

在IE6 +,FF 3.5 +,Chrome,Safari,Edge中测试

的HTML

1
Paste

的JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
var editableDiv = document.getElementById('editableDiv');

function handlepaste (e) {
    var types, pastedData, savedContent;

    // Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+)
    if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {

        // Check for 'text/html' in types list. See abligh's answer below for deatils on
        // why the DOMStringList bit is needed. We cannot fall back to 'text/plain' as
        // Safari/Edge don't advertise HTML data even if it is available
        types = e.clipboardData.types;
        if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {

            // Extract data and pass it to callback
            pastedData = e.clipboardData.getData('text/html');
            processPaste(editableDiv, pastedData);

            // Stop the data from actually being pasted
            e.stopPropagation();
            e.preventDefault();
            return false;
        }
    }

    // Everything else: Move existing element contents to a DocumentFragment for safekeeping
    savedContent = document.createDocumentFragment();
    while(editableDiv.childNodes.length > 0) {
        savedContent.appendChild(editableDiv.childNodes[0]);
    }

    // Then wait for browser to paste content into it and cleanup
    waitForPastedData(editableDiv, savedContent);
    return true;
}

function waitForPastedData (elem, savedContent) {

    // If data has been processes by browser, process it
    if (elem.childNodes && elem.childNodes.length > 0) {

        // Retrieve pasted content via innerHTML
        // (Alternatively loop through elem.childNodes or elem.getElementsByTagName here)
        var pastedData = elem.innerHTML;

        // Restore saved content
        elem.innerHTML ="";
        elem.appendChild(savedContent);

        // Call callback
        processPaste(elem, pastedData);
    }

    // Else wait 20ms and try again
    else {
        setTimeout(function () {
            waitForPastedData(elem, savedContent)
        }, 20);
    }
}

function processPaste (elem, pastedData) {
    // Do whatever with gathered data;
    alert(pastedData);
    elem.focus();
}

// Modern browsers. Note: 3rd argument is required for Firefox <= 6
if (editableDiv.addEventListener) {
    editableDiv.addEventListener('paste', handlepaste, false);
}
// IE <= 8
else {
    editableDiv.attachEvent('onpaste', handlepaste);
}

JSFiddle:https://jsfiddle.net/nicoburns/wrqmuabo/23/

说明

divonpaste事件具有附加的handlePaste函数,并传递了一个参数:粘贴事件的event对象。我们特别感兴趣的是此事件的clipboardData属性,该属性允许在非ie浏览器中访问剪贴板。在IE中,等效项为window.clipboardData,尽管它的API略有不同。

请参阅下面的资源部分。

handlePaste函数:

此功能有两个分支。

第一个检查event.clipboardData是否存在,并检查它的types属性是否包含'text / html'(types可以是使用contains方法检查的DOMStringList,也可以是字符串使用indexOf方法检查)。如果所有这些条件都满足,那么我们按照解决方案#1进行,除了使用'text / html'而不是'text / plain'。目前,该功能适用??于Chrome和Firefox 22+。

如果不支持此方法(所有其他浏览器),那么我们

  • 将元素的内容保存到DocumentFragment
  • 清空元素
  • 调用waitForPastedData函数
  • waitforpastedata函数:

    此功能首先轮询粘贴的数据(每20毫秒一次),这是必需的,因为它不会立即出现。数据出现后:

  • 将可编辑div的innerHTML(现在是粘贴的数据)保存到变量中
  • 恢复保存在DocumentFragment中的内容
  • 使用检索到的数据调用" processPaste"函数
  • processpaste函数:

    对粘贴的数据进行任意处理。在这种情况下,我们只是提醒数据,您可以做任何您想做的事。您可能需要通过某种数据清理过程来运行粘贴的数据。

    保存和还原光标位置

    在实际情况中,您可能希望先保存选择,然后再保存选择(在contentEditable上设置光标位置)。然后,您可以在用户启动粘贴操作时将粘贴的数据插入光标所在的位置。

    资源:

    • MDN粘贴事件:https://developer.mozilla.org/en-US/docs/Web/Events/paste
    • MSDN剪贴板:https://msdn.microsoft.com/zh-cn/library/ms535220(v=vs.85).aspx
    • MDN DocumentFragment:https://developer.mozilla.org/en/docs/Web/API/DocumentFragment
    • MDN DomStringList:https://developer.mozilla.org/en/docs/Web/API/DOMStringList

    感谢Tim Down建议使用DocumentFragment,并感谢由于使用DOMStringList而不是剪贴板数据的字符串而在Firefox中捕获错误。


    自从编写此答案以来,情况已经发生了变化:由于Firefox已在版本22中添加了支持,因此所有主要的浏览器现在都支持在粘贴事件中访问剪贴板数据。有关示例,请参见Nico Burns的答案。

    过去,这通常不可能以跨浏览器的方式实现。理想的方法是能够通过paste事件获取粘贴的内容,这在最新的浏览器中是可能的,但在某些较旧的浏览器(尤其是Firefox <22)中则不能。

    当您需要支持较旧的浏览器时,您可以做的事情很多,而且有些hack可以在Firefox 2 +,IE 5.5+和WebKit浏览器(例如Safari或Chrome)中使用。 TinyMCE和CKEditor的最新版本都使用此技术:

  • 使用按键事件处理程序检测ctrl-v / shift-ins事件
  • 在该处理程序中,保存当前用户选择,在屏幕外(例如,左-1000px处)向文档添加textarea元素,关闭designMode并在textarea上调用focus(),从而移动插入符号并有效地重定向糊
  • 在事件处理程序中设置一个非常简短的计时器(例如1毫秒),以调用另一个函数,该函数存储textarea值,从文档中删除textarea,重新打开designMode,恢复用户选择并粘贴文本。
  • 请注意,这仅适用于键盘粘贴事件,不适用于上下文或编辑菜单中的粘贴。在粘贴事件触发时,将插入符号重定向到文本区域(至少在某些浏览器中)为时已晚。

    万一需要支持Firefox 2,请注意,您需要将textarea放在父文档中,而不是在该浏览器中放置WYSIWYG编辑器iframe的文档。


    简单版本:

    1
    2
    3
    4
    5
    document.querySelector('[contenteditable]').addEventListener('paste', (e) => {
        e.preventDefault();
        const text = (e.originalEvent || e).clipboardData.getData('text/plain');
        window.document.execCommand('insertText', false, text);
    });

    使用clipboardData

    演示:http://jsbin.com/nozifexasu/edit?js,输出

    Edge,Firefox,Chrome,Safari,Opera经过测试。

    注意:请记住也要在服务器端检查输入/输出(如PHP剥离标签)


    现场演示

    已在Chrome / FF / IE11上测试

    Chrome / IE令人讨厌的是,这些浏览器为每行添加元素。这里有一篇关于此的文章,可以通过将contenteditable元素设置为display:inline-block来解决。

    选择一些突出显示的HTML并将其粘贴到此处:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function onPaste(e){
      var content;
      e.preventDefault();

      if( e.clipboardData ){
        content = e.clipboardData.getData('text/plain');
        document.execCommand('insertText', false, content);
        return false;
      }
      else if( window.clipboardData ){
        content = window.clipboardData.getData('Text');
        if (window.getSelection)
          window.getSelection().getRangeAt(0).insertNode( document.createTextNode(content) );
      }
    }


    /////// EVENT BINDING /////////
    document.querySelector('[contenteditable]').addEventListener('paste', onPaste);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [contenteditable]{
      /* chroem bug: https://stackoverflow.com/a/24689420/104380 */
      display:inline-block;
      width: calc(100% - 40px);
      min-height:120px;
      margin:10px;
      padding:10px;
      border:1px dashed green;
    }

    /*
     mark HTML inside the"contenteditable"  
     (Shouldn't be any OFC!)'
    */

    [contenteditable] *{
      background-color:red;
    }
    1
     


    在这里,我已经用屏幕外的文本区域为Tim Downs提案写了一些概念证明。代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    <html>
    <head>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js">
    <script language="JavaScript">
     $(document).ready(function()
    {

    var ctrlDown = false;
    var ctrlKey = 17, vKey = 86, cKey = 67;

    $(document).keydown(function(e)
    {
        if (e.keyCode == ctrlKey) ctrlDown = true;
    }).keyup(function(e)
    {
        if (e.keyCode == ctrlKey) ctrlDown = false;
    });

    $(".capture-paste").keydown(function(e)
    {
        if (ctrlDown && (e.keyCode == vKey || e.keyCode == cKey)){
            $("#area").css("display","block");
            $("#area").focus();        
        }
    });

    $(".capture-paste").keyup(function(e)
    {
        if (ctrlDown && (e.keyCode == vKey || e.keyCode == cKey)){                      
            $("#area").blur();
            //do your sanitation check or whatever stuff here
            $("#paste-output").text($("#area").val());
            $("#area").val("");
            $("#area").css("display","none");
        }
    });

    });


    </head>
    <body class="capture-paste">




       
        <textarea id="area" style="display: none; position: absolute; left: -99em;"></textarea>
       

    </body>
    </html>

    只需将整个代码复制并粘贴到一个html文件中,然后尝试从文档的任何位置的剪贴板粘贴(使用ctrl-v)文本。

    我已经在IE9和Firefox,Chrome和Opera的新版本中对其进行了测试。效果很好。也可以使用他喜欢的任何组合键来触发此功能,这也很好。当然,不要忘记包括jQuery源。

    随时使用此代码,如果您有一些改进或问题,请发回。还要注意,我不是Java语言开发人员,所以我可能错过了一些东西(=>做自己的见证)。


    基于l2aelba anwser。已在FF,Safari,Chrome,IE(8、9、10和11)上进行了测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
        $("#editText").on("paste", function (e) {
            e.preventDefault();

            var text;
            var clp = (e.originalEvent || e).clipboardData;
            if (clp === undefined || clp === null) {
                text = window.clipboardData.getData("text") ||"";
                if (text !=="") {
                    if (window.getSelection) {
                        var newNode = document.createElement("span");
                        newNode.innerHTML = text;
                        window.getSelection().getRangeAt(0).insertNode(newNode);
                    } else {
                        document.selection.createRange().pasteHTML(text);
                    }
                }
            } else {
                text = clp.getData('text/plain') ||"";
                if (text !=="") {
                    document.execCommand('insertText', false, text);
                }
            }
        });


    这个不使用任何setTimeout()。

    我已经使用这篇出色的文章来实现跨浏览器支持。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    $(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);
        }
    });

    粘贴之前,此代码使用选择句柄进行了扩展:
    演示


    为了清除粘贴的文本并将当前选定的文本替换为粘贴的文本,这很简单:

    1
    Paste

    JS:

    1
    2
    3
    4
    function handlepaste(el, e) {
      document.execCommand('insertText', false, e.clipboardData.getData('text/plain'));
      e.preventDefault();
    }


    这应该在所有支持onpaste事件和变异观察者的浏览器上都可以使用。

    该解决方案超越了仅获取文本的范围,它实际上允许您在粘贴的内容粘贴到元素之前对其进行编辑。

    它通过使用contenteditable的onpaste事件(受所有主要浏览器支持)和突变观察者(受Chrome,Firefox和IE11 +支持)来工作

    第1步

    创建具有contenteditable的HTML元素

    1
     

    第2步

    在您的Javascript代码中添加以下事件

    1
    document.getElementById("target_paste_element").addEventListener("paste", pasteEventVerifierEditor.bind(window, pasteCallBack), false);

    我们需要绑定pasteCallBack,因为变异观察者将被异步调用。

    第三步

    在代码中添加以下功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    function pasteEventVerifierEditor(callback, e)
    {
       //is fired on a paste event.
        //pastes content into another contenteditable div, mutation observer observes this, content get pasted, dom tree is copied and can be referenced through call back.
        //create temp div
        //save the caret position.
        savedCaret = saveSelection(document.getElementById("target_paste_element"));

        var tempDiv = document.createElement("div");
        tempDiv.id ="id_tempDiv_paste_editor";
        //tempDiv.style.display ="none";
        document.body.appendChild(tempDiv);
        tempDiv.contentEditable ="true";

        tempDiv.focus();

        //we have to wait for the change to occur.
        //attach a mutation observer
        if (window['MutationObserver'])
        {
            //this is new functionality
            //observer is present in firefox/chrome and IE11
            // select the target node
            // create an observer instance
            tempDiv.observer = new MutationObserver(pasteMutationObserver.bind(window, callback));
            // configuration of the observer:
            var config = { attributes: false, childList: true, characterData: true, subtree: true };

            // pass in the target node, as well as the observer options
            tempDiv.observer.observe(tempDiv, config);

        }  

    }



    function pasteMutationObserver(callback)
    {

        document.getElementById("id_tempDiv_paste_editor").observer.disconnect();
        delete document.getElementById("id_tempDiv_paste_editor").observer;

        if (callback)
        {
            //return the copied dom tree to the supplied callback.
            //copy to avoid closures.
            callback.apply(document.getElementById("id_tempDiv_paste_editor").cloneNode(true));
        }
        document.body.removeChild(document.getElementById("id_tempDiv_paste_editor"));

    }

    function pasteCallBack()
    {
        //paste the content into the element.
        restoreSelection(document.getElementById("target_paste_element"), savedCaret);
        delete savedCaret;

        pasteHtmlAtCaret(this.innerHTML, false, true);
    }  


    saveSelection = function(containerEl) {
    if (containerEl == document.activeElement)
    {
        var range = window.getSelection().getRangeAt(0);
        var preSelectionRange = range.cloneRange();
        preSelectionRange.selectNodeContents(containerEl);
        preSelectionRange.setEnd(range.startContainer, range.startOffset);
        var start = preSelectionRange.toString().length;

        return {
            start: start,
            end: start + range.toString().length
        };
    }
    };

    restoreSelection = function(containerEl, savedSel) {
        containerEl.focus();
        var charIndex = 0, range = document.createRange();
        range.setStart(containerEl, 0);
        range.collapse(true);
        var nodeStack = [containerEl], node, foundStart = false, stop = false;

        while (!stop && (node = nodeStack.pop())) {
            if (node.nodeType == 3) {
                var nextCharIndex = charIndex + node.length;
                if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
                    range.setStart(node, savedSel.start - charIndex);
                    foundStart = true;
                }
                if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
                    range.setEnd(node, savedSel.end - charIndex);
                    stop = true;
                }
                charIndex = nextCharIndex;
            } else {
                var i = node.childNodes.length;
                while (i--) {
                    nodeStack.push(node.childNodes[i]);
                }
            }
        }

        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }

    function pasteHtmlAtCaret(html, returnInNode, selectPastedContent) {
    //function written by Tim Down

    var sel, range;
    if (window.getSelection) {
        // IE9 and non-IE
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();

            // Range.createContextualFragment() would be useful here but is
            // only relatively recently standardized and is not supported in
            // some browsers (IE9, for one)
            var el = document.createElement("div");
            el.innerHTML = html;
            var frag = document.createDocumentFragment(), node, lastNode;
            while ( (node = el.firstChild) ) {
                lastNode = frag.appendChild(node);
            }
            var firstNode = frag.firstChild;
            range.insertNode(frag);

            // Preserve the selection
            if (lastNode) {
                range = range.cloneRange();
                if (returnInNode)
                {
                    range.setStart(lastNode, 0); //this part is edited, set caret inside pasted node.
                }
                else
                {
                    range.setStartAfter(lastNode);
                }
                if (selectPastedContent) {
                    range.setStartBefore(firstNode);
                } else {
                    range.collapse(true);
                }
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    } else if ( (sel = document.selection) && sel.type !="Control") {
        // IE < 9
        var originalRange = sel.createRange();
        originalRange.collapse(true);
        sel.createRange().pasteHTML(html);
        if (selectPastedContent) {
            range = sel.createRange();
            range.setEndPoint("StartToStart", originalRange);
            range.select();
        }
    }

    }

    代码的作用是:

  • 有人使用ctrl-v,contextmenu或其他方式触发粘贴事件
  • 在粘贴事件中,将创建一个具有contenteditable的新元素(具有contenteditable的元素具有提升的特权)
  • 目标元素的插入符位置已保存。
  • 焦点设置为新元素
  • 内容被粘贴到新元素中并在DOM中呈现。
  • 变异观察者抓住了这一点(它注册了对dom树和内容的所有更改)。然后触发突变事件。
  • 粘贴内容的dom被克隆到变量中并返回到回调。临时元素被破坏。
  • 回调接收克隆的DOM。插入符号已恢复。您可以对其进行编辑,然后再将其附加到目标中。元件。在此示例中,我使用Tim Downs函数保存/还原插入符号并将HTML粘贴到元素中。
  • 非常感谢Tim Down
    看到这篇文章的答案:

    获取粘贴事件中文档上的粘贴内容


    对我有用的解决方案是,如果您要粘贴到文本输入,则将事件侦听器添加到粘贴事件。
    由于粘贴事件发生在输入中的文本更改之前,因此在我的粘贴处理程序中,我创建了一个延迟函数,在其中检查粘贴中输入框中发生的更改:

    1
    2
    3
    4
    5
    6
    7
    onPaste: function() {
        var oThis = this;
        setTimeout(function() { // Defer until onPaste() is done
            console.log('paste', oThis.input.value);
            // Manipulate pasted input
        }, 1);
    }


    对于Nico的答案发表评论的时间太长了,我认为该评论不再适用于Firefox(根据评论),对Safari而言,它对我也不起作用。

    首先,您现在似乎可以直接从剪贴板读取。而不是像这样的代码:

    1
    2
    3
    4
    if (/text\/plain/.test(e.clipboardData.types)) {
        // shouldn't this be writing to elem.value for text/plain anyway?
        elem.innerHTML = e.clipboardData.getData('text/plain');
    }

    采用:

    1
    2
    3
    4
    5
    6
    types = e.clipboardData.types;
    if (((types instanceof DOMStringList) && types.contains("text/plain")) ||
        (/text\/plain/.test(types))) {
        // shouldn't this be writing to elem.value for text/plain anyway?
        elem.innerHTML = e.clipboardData.getData('text/plain');
    }

    因为Firefox具有一个types字段,该字段是一个未实现testDOMStringList

    除非焦点位于contenteditable=true字段中,否则下一个Firefox将不允许粘贴。

    最后,除非焦点位于textarea(或者不仅是contenteditable=true)而且是:textarea(或输入)上,否则Firefox将不允许可靠地粘贴。

    • 不是display:none
    • 不是visibility:hidden
    • 大小不为零

    我正在尝试隐藏文本字段,以便可以通过JS VNC仿真器进行粘贴工作(即它要发送到远程客户端,并且实际上没有要粘贴的textarea等)。我发现尝试隐藏上面的文本字段有时会出现一些症状,但是通常在第二次粘贴时失败(或者在清除该字段以防止两次粘贴相同的数据时失败),因为该字段失去了焦点并且无法正确恢复尽管focus()。我想到的解决方案是将其放置在z-order: -1000上,将其设置为display:none,将其设置为1px x 1px,并将所有颜色设置为透明。 uck

    在Safari上,适用以上第二部分,即您需要具有textarea而不是display:none


    首先想到的是Google闭包库的pastehandler
    http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html


    简单的解决方案:

    1
    2
    3
    4
    document.onpaste = function(e) {
        var pasted = e.clipboardData.getData('Text');
        console.log(pasted)
    }

    这为我工作:

    1
    2
    3
    4
    5
    6
    function onPasteMe(currentData, maxLen) {
        // validate max length of pasted text
        var totalCharacterCount = window.clipboardData.getData('Text').length;
    }

    <input type="text" onPaste="return onPasteMe(this, 50);" />


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

    只需让浏览器像往常一样在其内容可编辑div中粘贴,然后在粘贴之后将用于自定义文本样式的所有span元素与文本本身交换即可。在Internet Explorer和我尝试过的其他浏览器中,这似乎可以正常工作。

    1
    2
    3
    4
    5
    6
    7
    $('[contenteditable]').on('paste', function (e) {
        setTimeout(function () {
            $(e.target).children('span').each(function () {
                $(this).replaceWith($(this).text());
            });
        }, 0);
    });

    该解决方案假定您正在运行jQuery,并且您不希望任何内容可编辑div中的文本格式设置。

    好的一面是它非常简单。


    该解决方案是替换html标签,它简单易用且跨浏览器;检查此jsfiddle:http://jsfiddle.net/tomwan/cbp1u2cx/1/,核心代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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过滤器做一些工作,因为此解决方案无法过滤'<< >>'这样的字符串


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function myFunct( e ){
        e.preventDefault();

        var pastedText = undefined;
        if( window.clipboardData && window.clipboardData.getData ){
        pastedText = window.clipboardData.getData('Text');
    }
    else if( e.clipboardData && e.clipboardData.getData ){
        pastedText = e.clipboardData.getData('text/plain');
    }

    //work with text

    }
    document.onpaste = myFunct;

    您可以通过以下方式执行此操作:

    使用此jQuery插件进行粘贴前和粘贴后事件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $.fn.pasteEvents = function( delay ) {
        if (delay == undefined) delay = 20;
        return $(this).each(function() {
            var $el = $(this);
            $el.on("paste", function() {
                $el.trigger("prepaste");
                setTimeout(function() { $el.trigger("postpaste"); }, delay);
            });
        });
    };

    现在您可以使用此插件;:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    $('#txt').on("prepaste", function() {

        $(this).find("*").each(function(){

            var tmp=new Date.getTime();
            $(this).data("uid",tmp);
        });


    }).pasteEvents();

    $('#txt').on("postpaste", function() {


      $(this).find("*").each(function(){

         if(!$(this).data("uid")){
            $(this).removeClass();
              $(this).removeAttr("style id");
          }
        });
    }).pasteEvents();

    讲解

    首先,将所有现有元素的uid设置为data属性。

    然后比较所有节点的POST PASTE事件。因此,通过比较,您可以识别新插入的元素,因为它们将具有uid,然后只需从新创建的元素中删除style / class / id属性,即可保留较旧的格式。


    这是上面发布的现有代码,但我已针对IE对其进行了更新,该错误是当选择现有文本并粘贴不会删除所选内容。以下代码已修复此问题

    1
    selRange.deleteContents();

    请参阅下面的完整代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $('[contenteditable]').on('paste', function (e) {
        e.preventDefault();

        if (window.clipboardData) {
            content = window.clipboardData.getData('Text');        
            if (window.getSelection) {
                var selObj = window.getSelection();
                var selRange = selObj.getRangeAt(0);
                selRange.deleteContents();                
                selRange.insertNode(document.createTextNode(content));
            }
        } else if (e.originalEvent.clipboardData) {
            content = (e.originalEvent || e).clipboardData.getData('text/plain');
            document.execCommand('insertText', false, content);
        }        
    });