JavaScript中如何复制到剪贴板?

4346

这仍然没有得到完美的支持。您可以在Can I use Clipboard API上查看支持情况,该网站详细介绍了W3C Clipboard APIs document的支持情况。 - mkobit
27个回答

46

我非常成功地使用这个(不需要 jQuery 或任何其他框架)。

function copyToClp(txt){
    var m = document;
    txt = m.createTextNode(txt);
    var w = window;
    var b = m.body;
    b.appendChild(txt);
    if (b.createTextRange) {
        var d = b.createTextRange();
        d.moveToElementText(txt);
        d.select();
        m.execCommand('copy');
    } 
    else {
        var d = m.createRange();
        var g = w.getSelection;
        d.selectNodeContents(txt);
        g().removeAllRanges();
        g().addRange(d);
        m.execCommand('copy');
        g().removeAllRanges();
    }
    txt.remove();
}

警告

在Chrome中,制表符会被转换为空格。


不适用于Firefox,我收到了一个错误提示,说缺少用户激活。 - Luke_
@Luke_ Firefox对吗?你是不是在没有直接用户点击的情况下调用它了? - Grim
在FF 111.0.1(64位)中没有问题。 - Josem

38

在 JavaScript/TypeScript 中,使用此命令的最佳且简单的方式为:

navigator.clipboard.writeText(textExample);

只需将您想要复制到剪贴板的值传递给textExample


1
navigator.clipboard 可能未定义。您应该捕获此异常... - Daniel
2
不支持IOS。 - Lowis
1
根据 MDN Clipboard 文档(https://developer.mozilla.org/en-US/docs/Web/API/Clipboard),此功能仅在安全上下文(HTTPS)中,在某些或所有支持的浏览器中可用。 - vesmihaylov
看到一个一行解决方案总是很不错。所选的答案还可以,但有时候在尝试让某些东西工作时,长篇回答可能会太多了。 - carloswm85

37

ZeroClipboard是我发现的最好的跨浏览器解决方案:

<div id="copy" data-clipboard-text="Copy Me!">Click to copy</div>
<script src="ZeroClipboard.js"></script>
<script>
  var clip = new ZeroClipboard( document.getElementById('copy') );
</script>

如果您需要为iOS提供非Flash支持,只需添加后备方案:

clip.on( 'noflash', function ( client, args ) {
    $("#copy").click(function(){
        var txt = $(this).attr('data-clipboard-text');
        prompt ("Copy link, then click OK.", txt);
    });
});

http://zeroclipboard.org/

https://github.com/zeroclipboard/ZeroClipboard


27
跨浏览器使用Flash?在iOS和Android 4.4上不起作用。 - Raptor
1
请查看更新后的答案。这样可以减少Flash用户的步骤,并为其他人提供备选方案。 - Justin
11
它有十亿行代码,这绝对是荒谬的。最好不要在项目中包含这样一个怪物,而是选择完全避免。 - vsync
2
有一个简单版本 https://gist.github.com/JamesMGreene/8698897,只有20K,没有74k版本中的所有功能。两个版本都不是很大。我猜测大多数用户都可以接受下载一个74k或20k文件所需的额外毫秒数,这样复制/粘贴就只需要一次点击而不是两次。 - Justin
@Justin 我就是无法在本地使其工作,即使我复制并粘贴示例(我进行最小更改,例如在脚本标记中更改src的值)。我觉得他们的文档很漂亮但效率低下。 - Gui Imamura

31

自从Chrome 42+和Firefox 41+现在支持document.execCommand('copy')命令,我创建了一些函数,使用Tim Down的旧回答Google开发者的回答的组合实现了跨浏览器复制到剪贴板的功能:

function selectElementContents(el) {
    // Copy textarea, pre, div, etc.
    if (document.body.createTextRange) {
        // Internet Explorer
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.select();
        textRange.execCommand("Copy");
    }
    else if (window.getSelection && document.createRange) {
        // Non-Internet Explorer
        var range = document.createRange();
        range.selectNodeContents(el);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
        try {
            var successful = document.execCommand('copy');
            var msg = successful ? 'successful' : 'unsuccessful';
            console.log('Copy command was ' + msg);
        }
        catch (err) {
            console.log('Oops, unable to copy');
        }
    }
} // end function selectElementContents(el)

function make_copy_button(el) {
    var copy_btn = document.createElement('input');
    copy_btn.type = "button";
    el.parentNode.insertBefore(copy_btn, el.nextSibling);
    copy_btn.onclick = function() {
        selectElementContents(el);
    };

    if (document.queryCommandSupported("copy") || parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 42) {
        // Copy works with Internet Explorer 4+, Chrome 42+, Firefox 41+, Opera 29+
        copy_btn.value = "Copy to Clipboard";
    }
    else {
        // Select only for Safari and older Chrome, Firefox and Opera
        copy_btn.value = "Select All (then press Ctrl + C to Copy)";
    }
}
/* Note: document.queryCommandSupported("copy") should return "true" on browsers that support copy,
    but there was a bug in Chrome versions 42 to 47 that makes it return "false".  So in those
    versions of Chrome feature detection does not work!
    See https://code.google.com/p/chromium/issues/detail?id=476508
*/

make_copy_button(document.getElementById("markup"));
<pre id="markup">
  Text that can be copied or selected with cross browser support.
</pre>


26

我认为这是最好的解决方案。

  • 使用cssText而不是直接设置样式,避免在Internet Explorer中出现异常。
  • 如果存在选择,则恢复选择。
  • 将只读属性设置为“true”,以防止移动设备上弹出键盘。
  • 对于iOS有一个解决方法,使其正常工作,因为它通常会阻止execCommand命令。

以下是代码:

const copyToClipboard = (function initClipboardText() {
  const textarea = document.createElement('textarea');

  // Move it off-screen.
  textarea.style.cssText = 'position: absolute; left: -99999em';

  // Set to readonly to prevent mobile devices opening a keyboard when
  // text is .select()'ed.
  textarea.setAttribute('readonly', true);

  document.body.appendChild(textarea);

  return function setClipboardText(text) {
    textarea.value = text;

    // Check if there is any content selected previously.
    const selected = document.getSelection().rangeCount > 0 ?
      document.getSelection().getRangeAt(0) : false;

    // iOS Safari blocks programmatic execCommand copying normally, without this hack.
    // https://dev59.com/ulsX5IYBdhLWcg3wRNjK
    if (navigator.userAgent.match(/ipad|ipod|iphone/i)) {
      const editable = textarea.contentEditable;
      textarea.contentEditable = true;
      const range = document.createRange();
      range.selectNodeContents(textarea);
      const sel = window.getSelection();
      sel.removeAllRanges();
      sel.addRange(range);
      textarea.setSelectionRange(0, 999999);
      textarea.contentEditable = editable;
    }
    else {
      textarea.select();
    }

    try {
      const result = document.execCommand('copy');

      // Restore previous selection.
      if (selected) {
        document.getSelection().removeAllRanges();
        document.getSelection().addRange(selected);
      }

      return result;
    }
    catch (err) {
      console.error(err);
      return false;
    }
  };
})();

使用方法: copyToClipboard('一些文本')


不支持Opera等浏览器。 - Khom Nazid

26

其他方法会将纯文本复制到剪贴板。要复制HTML(即,您可以将结果粘贴到所见即所得编辑器中),只能在Internet Explorer中执行以下操作。这与其他方法根本不同,因为浏览器实际上可见地选择内容。

// Create an editable DIV and append the HTML content you want copied
var editableDiv = document.createElement("div");
with (editableDiv) {
    contentEditable = true;
}
editableDiv.appendChild(someContentElement);

// Select the editable content and copy it to the clipboard
var r = document.body.createTextRange();
r.moveToElementText(editableDiv);
r.select();
r.execCommand("Copy");

// Deselect, so the browser doesn't leave the element visibly selected
r.moveToElementText(someHiddenDiv);
r.select();

1
在此处查看更完整的HTML解决方案:https://dev59.com/Q1sX5IYBdhLWcg3wJMnb - kofifus

26
我找到了以下的解决方案:
按键按下处理程序创建一个“pre”标签。我们将要复制的内容设置为该标签的内容,然后在此标签上进行选择并在处理程序中返回true。这会调用Chrome的标准处理程序并复制所选文本。
如果需要,您可以为恢复先前选择的函数设置超时。我的MooTools实现:
function EnybyClipboard() {
    this.saveSelection = false;
    this.callback = false;
    this.pastedText = false;

    this.restoreSelection = function() {
        if (this.saveSelection) {
            window.getSelection().removeAllRanges();
            for (var i = 0; i < this.saveSelection.length; i++) {
                window.getSelection().addRange(this.saveSelection[i]);
            }
            this.saveSelection = false;
        }
    };

    this.copyText = function(text) {
        var div = $('special_copy');
        if (!div) {
            div = new Element('pre', {
                'id': 'special_copy',
                'style': 'opacity: 0;position: absolute;top: -10000px;right: 0;'
            });
            div.injectInside(document.body);
        }
        div.set('text', text);
        if (document.createRange) {
            var rng = document.createRange();
            rng.selectNodeContents(div);
            this.saveSelection = [];
            var selection = window.getSelection();
            for (var i = 0; i < selection.rangeCount; i++) {
                this.saveSelection[i] = selection.getRangeAt(i);
            }
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(rng);
            setTimeout(this.restoreSelection.bind(this), 100);
        } else return alert('Copy did not work. :(');
    };

    this.getPastedText = function() {
        if (!this.pastedText) alert('Nothing to paste. :(');
        return this.pastedText;
    };

    this.pasteText = function(callback) {
        var div = $('special_paste');
        if (!div) {
            div = new Element('textarea', {
                'id': 'special_paste',
                'style': 'opacity: 0;position: absolute;top: -10000px;right: 0;'
            });
            div.injectInside(document.body);
            div.addEvent('keyup', function() {
                if (this.callback) {
                    this.pastedText = $('special_paste').get('value');
                    this.callback.call(null, this.pastedText);
                    this.callback = false;
                    this.pastedText = false;
                    setTimeout(this.restoreSelection.bind(this), 100);
                }
            }.bind(this));
        }
        div.set('value', '');
        if (document.createRange) {
            var rng = document.createRange();
            rng.selectNodeContents(div);
            this.saveSelection = [];
            var selection = window.getSelection();
            for (var i = 0; i < selection.rangeCount; i++) {
                this.saveSelection[i] = selection.getRangeAt(i);
            }
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(rng);
            div.focus();
            this.callback = callback;
        } else return alert('Failed to paste. :(');
    };
}

使用方法:

enyby_clip = new EnybyClipboard(); // Init

enyby_clip.copyText('some_text'); // Place this in the Ctrl+C handler and return true;

enyby_clip.pasteText(function callback(pasted_text) {
    alert(pasted_text);
}); // Place this in Ctrl+V handler and return true;

在粘贴时,它会创建一个文本区域并以相同的方式工作。

PS:也许这个解决方案可以用于创建一个完全跨浏览器的解决方案,而不需要使用 Flash。它在 Firefox 和 Chrome 中都可以使用。


2
有人尝试过这个吗?听起来很不错,如果它能在多种浏览器上真的能用! - Michael
1
http://jsfiddle.net/H2FHC/ 演示:http://fiddle.jshell.net/H2FHC/show/ 请打开并按Ctrl+V或Ctrl+C。在FF 19.0中完美分叉。在Chrome 25.0.1364.97 m中也是如此。Opera 12.14-OK。Windows的Safari 5.1.7-OK。IE-失败。 - Enyby
对于IE浏览器,需要将焦点放在页面内的元素上。请参见http://fiddle.jshell.net/H2FHC/3/show/和http://fiddle.jshell.net/H2FHC/3/。在IE 9/10中工作正常。但是,在IE 6/7中需要以其他方式创建选择区域,因为不支持document.createRange。 - Enyby

24

我很不情愿再增加一篇回答,但出于帮助像我这样的新手,并且因为这是谷歌搜索结果排名最高的,我将提供以下信息。

2022年复制文本到剪贴板只需要使用一行代码

navigator.clipboard.writeText(textToCopy);

如果复制成功,则返回一个已解决的Promise,否则返回已拒绝的Promise。

以下是完整可用的函数:

async function copyTextToClipboard(textToCopy) {
    try {
        await navigator.clipboard.writeText(textToCopy);
        console.log('copied to clipboard')
    } catch (error) {
        console.log('failed to copy to clipboard. error=' + error);
    }
}

警告!如果您在测试此内容时打开了Chrome Dev Tools,则会失败,因为浏览器需要将窗口放在焦点中才能启用剪贴板。这是为了防止不想要的随机网站更改您的剪贴板。Dev Tools会夺取此焦点,因此关闭Dev Tools后,您的测试将正常工作。

如果您想复制其他内容(图像等)到剪贴板,请查看这些文档。

https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API

这在浏览器中得到了很好的支持,您可以使用它。如果您担心Firefox,请使用权限查询来显示或隐藏按钮(如果浏览器支持)。https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query


异步复制到剪贴板(){ let text = "剪贴板上的文本"; await navigator.clipboard.writeText(text);}调用此函数后,您将知道可以从剪贴板粘贴变量text的所需值到任何地方。 - Kartik Chandra

19

这段代码在2021年5月进行了测试,在Chrome、IE和Edge上都可以工作。下面的'message'参数是您想要复制的字符串值。

<script type="text/javascript">
    function copyToClipboard(message) {
        var textArea = document.createElement("textarea");
        textArea.value = message;
        textArea.style.opacity = "0"; 
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();


        try {
            var successful = document.execCommand('copy');
            var msg = successful ? 'successful' : 'unsuccessful';
            alert('Copying text command was ' + msg);
        } catch (err) {
            alert('Unable to copy value , error : ' + err.message);
        }

        document.body.removeChild(textArea);
    }

</script>

17

这可以直接使用最新的剪贴板API和用户交互,立刻生效:

copy.addEventListener("pointerdown", () => navigator.clipboard.writeText("Hello World!"))
<button id="copy">Copy Hello World!</button>


它不起作用。 - user31782
如果您在.writeText() 中添加.then(),则它将正常工作,因为它是一个 Promise。 - Andi Aleksandrov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接