复制当前网址到剪贴板

41

我今天不确定为什么这件事对我来说如此困难,但出于某种原因,我似乎无法将当前URL复制到剪贴板。总体而言,我正在寻找一种方法来实现它,而不需要创建一些隐藏的文本元素。

这是我目前尝试的:

var shareBtn = document.querySelector(".share-button");

shareBtn.addEventListener('click', function(event) {
  var cpLink = window.location.href;
  cpLink.select();

  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');
  }
  event.preventDefault;
});

当我使用.select()时,出现了错误:t.select不是函数。所以我不确定最好的解决方法是什么。再次说明,不能使用jQuery(或任何其他JS库),也不能使用某种隐藏文本字段。


因为它不是一个元素,所以你无法选择文本。 - epascarello
4
如果没有支持select()方法的虚拟元素,你实际上无法完成它。这让我感到惊奇,因为在浏览器有自己的支付集成API但缺少像剪贴板API这样基本功能的一年里。 - ppajer
那么,获取当前URL并将其复制到剪贴板的最佳方法是什么? - ultraloveninja
6个回答

91

您可以创建一个临时的DOM元素来保存URL

很遗憾,目前没有标准的API可供剪贴板操作使用,因此我们只能使用HTML input元素的hacky方式来满足我们的需求。想法是创建一个输入框,将其值设置为当前文档的URL,选择其内容并执行copy命令。

然后,我们会清理这个混乱的情况,而不是将输入框设置为隐藏状态并污染DOM。

var dummy = document.createElement('input'),
    text = window.location.href;

document.body.appendChild(dummy);
dummy.value = text;
dummy.select();
document.execCommand('copy');
document.body.removeChild(dummy);

2
啊哈,我懂了。这种情况下只能创建一个空对象然后再删除它,感觉有点儿蠢。但既然这是唯一的方法,那就这么办吧。 - ultraloveninja
2
是的,这很麻烦。我一直在查找选择API,也许可以找到一种模拟整个过程而无需输入的方法,但目前为止还没有成功。 - ppajer
哇,所以你只能在文本输入上使用execCommand吗?哇。 - Kyle Calica-St
1
只是想提一下,这种方法至少在Chrome中不起作用(或者至少在我使用模态框的情况下不起作用)。作为一种解决方法,可以预先创建一个隐藏字段,然后取消隐藏+更改值+复制+再次隐藏:详见 -> https://dev59.com/2lwZ5IYBdhLWcg3wVO5U#57192718 - TitanFighter
这应该是被接受的答案...虽然可能有些取巧,但它完美地运行。 - Diego Dorado

40

2021年更新:您可以使用剪贴板API,方法如下:

navigator.clipboard.writeText(window.location.href);

不适用于IOS。 - Lafi
我相信这里需要一些异步魔法。这是一个很棒的指南:https://web.dev/async-clipboard/ - ianp
@Lafi 它在 iOS 上确实可以工作。 - Leo

4

这可能是其中一种相对简单的实现方式。

window.navigator.clipboard.writeText(textToCopy);

4

ppajer的回答确实是当浏览器处理复制时所需的全部内容,无需涉及任何自定义剪贴板事件处理。

但是,如果您或某个库挂钩复制事件(例如,window.addEventListener('copy', ...)),并且该处理程序依赖于使用window.getSelection(),则19年的Firefox问题会使您受到影响。就像MDN说的那样

值得注意的是,目前getSelection()在Firefox、Edge(遗留版)和Internet Explorer中不能用于<textarea><input>元素的内容。

因此,在HTMLInputElement#select之后,getSelection()将返回非空结果,但没有提供实际选择的内容。通过使用非输入元素暂时保存URL轻松解决:

function copyUrl() {
  if (!window.getSelection) {
    alert('Please copy the URL from the location bar.');
    return;
  }
  const dummy = document.createElement('p');
  dummy.textContent = window.location.href;
  document.body.appendChild(dummy);

  const range = document.createRange();
  range.setStartBefore(dummy);
  range.setEndAfter(dummy);

  const selection = window.getSelection();
  // First clear, in case the user already selected some other text
  selection.removeAllRanges();
  selection.addRange(range);

  document.execCommand('copy');
  document.body.removeChild(dummy);
}

(如果没有自定义处理程序挂钩复制事件,上述方法也适用。)

0
var $temp = $("<input>");
var $url = $('.copy').attr('href');

  $('.clipboard').on('click', function() {
    $("body").append($temp);
    $temp.val($url).select();
    document.execCommand("copy");
    $temp.remove();
      const Toast = Swal.mixin({
        toast: true,
        position: 'top-end',
        showConfirmButton: false,
        timer: 3000,
        timerProgressBar: true,
        didOpen: (toast) => {
          toast.addEventListener('mouseenter', Swal.stopTimer)
          toast.addEventListener('mouseleave', Swal.resumeTimer)
        }
      })
        
      Toast.fire({
        icon: 'success',
        title: 'URL copied! ' 
      })
          
})

你的回答可以通过提供额外的支持性信息来改进。请[编辑]以添加更多细节,例如引用或文档,以便他人可以确认您的答案是否正确。您可以在帮助中心中找到有关如何编写好答案的更多信息。 - Ethan

0

我曾经遇到一个相似的问题,需要复制链接到我的DOM中的特定标题元素。

我基本上做的是:

  1. 获取链接URL和实际链接元素
  2. 启用本地剪贴板组件以复制实际HTML
  3. 将链接复制到标题中

Element.prototype.getLink = function () {
  let link = document.createElement("a");
  link.href = this.getUrl();
  link.innerText = this.innerText; 
  return link;
};

Element.prototype.getUrl = function () {
  return new URL(window.location.origin + window.location.pathname + '#' + this.id);
};

Clipboard.prototype.writeHTML = function (html, text) {
  let textContent = text || html.innerText;
  let htmlContent = "";
  if (typeof (html) == "string") htmlContent = html;
  else if (html instanceof Element) htmlContent = html.outerHTML;
  else htmlContent = html.toString();

  if (ClipboardItem) //bug in firefox : https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem
  {
    let content = [
      new ClipboardItem({
        "text/html": new Blob([htmlContent], { type: "text/html" }), //this can be interpreted by applications like teams or office word
        "text/plain": new Blob([textContent], { type: "text/plain" }) //while this is required for other apps, like plain text editors
      })
    ];
    return this.write(content);
  }
  else {
    return this.writeText(textContent);
  }
};

let header = document.getElementById("some-header");
let button = document.getElementById("copy-button");
let feedback = document.getElementById("feedback");
button.addEventListener("click", function(){
  navigator.clipboard
    .writeHTML(header.getLink(), header.getUrl())
    .then(function () {
      feedback.innerText = "copied!"; 
    })
    .catch((error) => {
      feedback.innerText = `Oops... that shoudln't have happened. ${error}`; 
    });
});
<h4 id="some-header">Some Header</h4>
<button id="copy-button" role="button">Copy URL to Header</button>
<div id="feedback">nothing copied yet</div>


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