使用 execCommand (Javascript) 将隐藏文本复制到剪贴板

Posted

技术标签:

【中文标题】使用 execCommand (Javascript) 将隐藏文本复制到剪贴板【英文标题】:Using execCommand (Javascript) to copy hidden text to clipboard 【发布时间】:2015-10-14 02:37:03 【问题描述】:

我正在尝试在不使用 Flash 的情况下复制到剪贴板,如果浏览器与 javascript 方法不兼容,我计划使用 ZeroClipboard 回退到 Flash。

我有一个按钮的 onClick 侦听器,如下所示:

$(buttonWhereActionWillBeTriggered).click(function() 
    var copyDiv = document.getElementById(inputContainingTextToBeCopied);
    copyDiv.focus();
    document.execCommand('SelectAll');
    document.execCommand("Copy", false, null);

和一个输入字段如下:

<input type="text" name="Element To Be Copied" id="inputContainingTextToBeCopied" value="foo"/>

这目前按预期工作,但设计要求包含要复制的文本的字段是不可见的。我已经尝试过设置type="hidden"style="display: none" 都没有成功。两者都会导致按钮选择整个页面并将整个内容复制到用户的剪贴板。 我相对确信原因不是基于浏览器的,但以防万一,我正在 Mac OS X 10.10.4 上的 Chrome(版本 43.0.2357.134(64 位))上进行测试。

有没有一种方法可以在隐藏 的同时保持其可见性?或者如果不是我可以采取的替代路线?


我知道类似的问题,但没有一个能解决我的问题,要么是太旧,要么没有真正使用 Javascript,要么不适合特定的场景。 Here's a good answer 对于任何有类似但不太具体的问题的人。

【问题讨论】:

你试过 opacity: 0 吗? @DavidDomain 我刚刚尝试过,它可以工作,太棒了,谢谢!但不幸的是,它仍然会留下透明 div 并移动设计,如果没有更好的解决方案,我会继续这样做并将输入字段设置为 1px x 1px。如果你想回答我会很乐意接受,如果没有更好的出现。再次感谢! 如果你使用 jQuery 来 show() 输入,然后调用 copy,然后立即再次 hide() 呢? @pokkanome 我采取了与此非常相似的路线,我会尽快发布答案,谢谢! 我使用 style="position: absolute; top: -999px; left: -999px" 【参考方案1】:

这是我不使用 jQuery 的解决方案:

function setClipboard(value) 
    var tempInput = document.createElement("input");
    tempInput.style = "position: absolute; left: -1000px; top: -1000px";
    tempInput.value = value;
    document.body.appendChild(tempInput);
    tempInput.select();
    document.execCommand("copy");
    document.body.removeChild(tempInput);
<!DOCTYPE html>
<html>
<head>
<title>Set Clipboard</title>
</head>
<body>
    <button onclick="setClipboard('foo loves bar')">Set Clipboard</button>
</body>
</html>

【讨论】:

它对我有用,丹,非常感谢。我搜索了这么多代码超过 2 小时,没有人为我工作。但你的代码很好。小而有效。再次感谢。 您好,我刚刚遇到了这个问题,几个小时以来一直在寻找这样的解决方案。如果没有 jQuery 的代码很好,那么这个脚本的头部是否需要任何外部链接/调用?因为现在我正在使用ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js 的google jQuery 文件,我是否需要参考其他文件才能使其正常工作?谢谢! 我的 sn-p 使用标准 Javascript 并且应该在现代网络浏览器中按原样工作。我会检查您的目标浏览器的 execComand 功能的浏览器兼容性(大多数都支持它):developer.mozilla.org/en-US/docs/Web/API/Document/… 如果您需要保留换行符,一个改进是创建一个“textarea”而不是“input”,在我的情况下,值来自隐藏的
(因此保留了换行符)
                
              
                
            
天哪,非常感谢。这完美地集成到我的代码中并且非常紧凑!【参考方案2】:

2019 - 仍在寻找没有屏幕外内容的答案。

我所做的是首先将输入文本字段更改为 type="text",复制文本然后将其更改回 type="hidden"。效果很好。

<input id="dummy" name="dummy" type="hidden">

<script>
var copyText = document.getElementById("dummy");
copyText.type = 'text';
copyText.select();
document.execCommand("copy");
copyText.type = 'hidden';
</script>

【讨论】:

这是迄今为止最简单、最好的解决方案。 这是最简单最好的解决方案。 优秀的解决方案老兄。 我们赢了。谢谢【参考方案3】:

--更新--

Document.execCommand()

[1] 在 Firefox 41 之前,需要在 user.js 首选项文件中启用剪贴板功能。请参阅Mozilla preferences for more information 的简要指南。如果不支持或启用该命令,则 execCommand 会引发异常而不是返回 false。在 Firefox 41 及更高版本中,剪贴板功能在任何能够弹出窗口(半可信脚本)的事件处理程序中默认启用。

因为Firefox version 41 Document.execCommand() 现在可以工作了。所以不再需要使用后备。


由于浏览器在剪贴板访问方面的行为似乎有所不同, 我花了一段时间才明白这一点。

它与您的解决方案非常相似,但不同之处在于创建一个临时元素并用输入 value 填充它。这样我们就可以将输入的display 属性设置为none

IE 也有一个解决方法,它使用window.clipboardData

Firefox 根本不允许我访问剪贴板。所以我不得不添加一个prompt 让用户手动复制输入值。当然prompt 很丑,但你可以只使用像窗口这样的模态框,它会做同样的事情。

由于这似乎是一件棘手的事情,我在 Win7(64 位) 并在

中进行了测试

Chrome - 版本 43.0.2357.134 m

IE - 版本 11.0.9600.17914

和 Firefox 无关,因为它无论如何都不会让我访问它。

var copyBtn   = $("#copy-btn"),
    input     = $("#copy-me");

function copyToClipboardFF(text) 
  window.prompt ("Copy to clipboard: Ctrl C, Enter", text);


function copyToClipboard() 
  var success   = true,
      range     = document.createRange(),
      selection;

  // For IE.
  if (window.clipboardData) 
    window.clipboardData.setData("Text", input.val());        
   else 
    // Create a temporary element off screen.
    var tmpElem = $('<div>');
    tmpElem.css(
      position: "absolute",
      left:     "-1000px",
      top:      "-1000px",
    );
    // Add the input value to the temp element.
    tmpElem.text(input.val());
    $("body").append(tmpElem);
    // Select temp element.
    range.selectNodeContents(tmpElem.get(0));
    selection = window.getSelection ();
    selection.removeAllRanges ();
    selection.addRange (range);
    // Lets copy.
    try  
      success = document.execCommand ("copy", false, null);
    
    catch (e) 
      copyToClipboardFF(input.val());
    
    if (success) 
      alert ("The text is on the clipboard, try to paste it!");
      // remove temp element.
      tmpElem.remove();
    
  


copyBtn.on('click', copyToClipboard);
#copy-me 
    display:none
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="Element To Be Copied" id="copy-me" value="foo loves bar"/>
<button id="copy-btn">Copy</button><br/><br/>
<textarea placeholder="paste here"></textarea>

【讨论】:

这是巨大的,只需将元素移出屏幕并使用 execCommand 函数将其复制...检查底部的答案。【参考方案4】:

感谢@DavidDomain 的帮助,我找到了一种有点老套但实用的方法。

首先,我将输入方式移出屏幕并修改了一些属性,结果如下:

<input type="text" name="Element To Be Copied" id="inputContainingTextToBeCopied" value="foo" style="display:none; position: relative; left: -10000px;"/>

对js进行以下修改后添加display:none

之后,@Pokkanome 的评论让我可以像这样修改 onClick 函数:

$(buttonWhereActionWillBeTriggered).click(function() 
    var copyDiv = document.getElementById(inputContainingTextToBeCopied);
    copyDiv.style.display = 'block';
    copyDiv.focus();
    document.execCommand('SelectAll');
    document.execCommand("Copy", false, null);
    copyDiv.style.display = 'none';

我不确定是否可以使用这种方法从隐藏的 div 复制,这在浏览器安全方面是有意义的,因为毫无疑问地访问剪贴板会有些风险。不过,所采取的方法具有相同的预期结果。

【讨论】:

【参考方案5】:

我在这里有一个不太过时的解决方案:

使用此脚本,您可以复制数据。它比过去提供的脚本要小得多。

脚本的作用是使用隐藏在屏幕一侧的输入,使用 CSS 或内联样式,然后快速选择它并运行复制命令。

function copyFunc() 
  var copyText = document.getElementById("copyInp");
  copyText.select();
  document.execCommand("copy"); //this function copies the text of the input with ID "copyInp"
<input type="text" value="StuffYaWantCopied" id="copyInp" style="position:absolute;left:-1000px;top:-1000px;">
  <a onclick="copyFunc()" style="cursor:cell;">
     Click here to Copy!
  </a>

对于 Bonus,我制作了一个小的剪贴板 API,它可以动态选择元素并使用 Contenteditable div 和动态变量从中检索文本:https://codepen.io/SkylerSpark/pen/OJJqxWX

另外,请参阅下面的 Ciprians Answer 关于使用新的 Permissions API 以用户允许的权限将文本直接发送到剪贴板,它不完全受支持,但它在最新的浏览器中可用(我知道它实际上适用于 chrome目前,但我还没有测试任何其他浏览器):https://***.com/a/58099014/11165703

【讨论】:

和我的想法一样,只是在屏幕上使用 css 隐藏输入元素 :) @aldrien.h 你知道如果你用 display: hidden 或类似的方式隐藏一个元素,就不能选择它吗?我希望你会。所以真的,除非你想通过使元素的每个部分都用透明颜色“隐藏”来添加更多的 CSS,否则你的想法是行不通的。 我的意思是,使用 css 在屏幕上隐藏,就像上面的样式一样,绝对位置在顶部和左侧具有负值,不显示:无,execCommand 将不适用于隐藏元素。 :) 实际上是@Dan Stevens 答案的副本,只是将样式放入元素而不是脚本中。 @VeenarM 这是你需要学习的东西,在***中,如果信息更可行,代码是否“相似”都没关系......我在这里添加的代码有数十亿份,但老实说,我不是抄写员,我自己写的 :P 而且我的剧本比 dans 短得多,不是为了竞争,而是事实。【参考方案6】:

您可以简单地使用 opacity:0.00000000000001 隐藏输入标签,然后使用 javascript 将隐藏的文本复制到剪贴板

function myFunction() 
  var copyText = document.getElementById("myInput");
  copyText.select();
  copyText.setSelectionRange(0, 99999)
  document.execCommand("copy");
  alert("Text copied successfully");
<input type="text" value="===your text here===" id="myInput" style="opacity:0.00000000000001">
<button onclick="myFunction()">Copy</button>

【讨论】:

Should you also make it have a width of 0 so it does not take up space?【参考方案7】:

另一种适用于所有浏览器的解决方法是,您可以使用绝对位置将其不透明度设置为 0,而不是隐藏元素。

#copy-me 
    position: absolute;
    opacity: 0;

【讨论】:

谢谢。这对我更有用,absolute 位置和-1000px 的解决方案topbottom 为我滚动。【参考方案8】:

您可以为此使用window.navigator

navigator.clipboard.writeText('this will be copied to the clipboard');

【讨论】:

这是最好和最现代的解决方案 兼容性:developer.mozilla.org/en-US/docs/Web/API/…【参考方案9】:

对我有用的是:

<div>
  <a class="copyBtn">Copy</a>
  <input class="d-none" value="teste">
</div>

和:

$('.copyBtn').on('click', function(e) 
  e.preventDefault();
  var input = $(this).parent().find(".dirVal");
  $(input).removeClass("d-none");
  input.select();

  document.execCommand('copy');
  $(input).addClass("d-none");
  callNotify("Parabéns!", "Caminho copiado para área de transferência!", "success");
);

【讨论】:

【参考方案10】:

用这个怎么样:https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText

navigator.clipboard.writeText("<empty clipboard>").then(function() 
  /* clipboard successfully set */
, function() 
  /* clipboard write failed */
);

【讨论】:

这取决于最前沿的Permissions API,所以目前可能不会被广泛支持。很高兴看到浏览器开发人员正在寻找支持剪贴板的正确方法,因此我们不依赖本主题中的“黑客”。【参考方案11】:

去做吧!

.blind 
    overflow: hidden;
    position: absolute;
    clip: rect(0 0 0 0);
    width: 1px;
    height: 1px;
    margin: -1px;

<textarea id="copy" class="blind">
your copy text here!
</textarea>
copyClipboard(document.getElementById('copy'));

function copyClipboard(el) 
  el.select();
  window.document.execCommand('copy');

https://gist.github.com/seunggabi/7ae53c100d647cb19c48047cff9b7019

【讨论】:

【参考方案12】:

两种对我有用的方法:

方法一: 在这种方法中,输入元素最初是隐藏的,复制功能将其取消隐藏,选择并复制文本,然后再次隐藏它。

<script>
  function copyLinkToClipboardViaHiddenField() 
    el = document.querySelector("#input");
    el.style.display = "block";
    var copyText = document.querySelector("#input");
    copyText.select();
    document.execCommand("copy");
    el.style.display = "none";
    document.getElementById("copylink").innerText = "copied OK!";
    document.getElementById("copylink").href = "";
    document.getElementById("copylink").style.color = "black";
    document.getElementById("copylink").style.textDecoration = "none";
    return false; // prevents click doing anything
  

</script>
<input id="input"
       type="text"
       style="display: none;"
       value="https://www.example.org/ViaHiddenField"/>
<a href="javascript:void(0)"
   onclick="return copyLinkToClipboardViaHiddenField()"
   id="copylink"
   style="text-decoration: underline;color: blue;">copy link ViaHiddenField</a>

方法 2: 在这种方法中,会创建一个新的输入元素并将其附加到文档正文的底部,复制其值,然后删除该元素。

<script>
  function copyLinkToClipboardViaAppendElement() 
    el = document.createElement("input");
    el.setAttribute('type', 'text');
    el.setAttribute('value', "https://www.example.org/ViaAppendElement");
    document.body.appendChild(el)
    el.select();
    console.log(el)
    document.execCommand("copy");
    el.parentNode.removeChild(el);
    document.getElementById("copylink").innerText = "copied OK!";
    document.getElementById("copylink").href = "";
    document.getElementById("copylink").style.color = "black";
    document.getElementById("copylink").style.textDecoration = "none";
    return false; // prevents click doing anything;
  

</script>
<a href="javascript:void(0)"
   onclick="return copyLinkToClipboardViaAppendElement()"
   id="copylink"
   style="text-decoration: underline;color: blue;">copy link ViaAppendElement</a>

【讨论】:

【参考方案13】:

要将文本复制到剪贴板,它必须是可见的。 所以我创建了一个 input type=text 但设置样式 display:none 并使用 jquery 执行 show() 和 hide() 围绕复制。

<input type=text id='me' value='bla' style='display:none;'>
<button onclick='
$("#me").show(); 
var copyText = document.getElementById("me"); 
copyText.select();
copyText.setSelectionRange(0, 99999);   
document.execCommand("copy"); 
$("#me").hide(); 
alert("Link copied to clipboard");
'></button> 

【讨论】:

【参考方案14】:

这是一个简单但很老套的答案,似乎对我有用。而不是使用display: none; 使用这个:

height: 0px;
width: 0px;
overflow: hidden;
position: absolute;

这允许选择,同时仍然隐藏文本区域并且不影响设计。

【讨论】:

我不会投反对票,因为这行得通。但是我会说,当你没有完全隐藏元素,或者至少将它移出屏幕时,它可能会导致选择错误......这很挑剔,虽然它在大多数情况下都可以工作,但现在你有一堆小 0pixel你看不到的屏幕上的元素。我知道这没有意义,但在极少数情况下,这可能是个坏主意,否则在正常使用时应该没问题。

以上是关于使用 execCommand (Javascript) 将隐藏文本复制到剪贴板的主要内容,如果未能解决你的问题,请参考以下文章

所见即所得 - execCommand 使用 HTML5 正确更改字体和字体大小

html 使用execCommands编辑浏览器中的HTML内容

javascript execCommand

有啥比 document.execCommand 更好的吗?

在 React 中使用 document.execCommand 将文本从 div 复制到剪贴板

用于 iOS webView 中标题的 document.execCommand