Использование execCommand (Javascript) для копирования скрытого текста в буфер обмена

Я пытаюсь скопировать в буфер обмена без использования Flash, я планирую вернуться на Flash с помощью ZeroClipboard, если браузер несовместим с подходом javascript.

У меня есть слушатель 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", ни один из которых не удалось. Оба приводят к тому, что кнопка выбирает всю страницу и копирует весь контент в пользовательский буфер обмена.
Я уверен, что причина не в браузере, а просто в том, что я тестирую Chrome (версия 43.0.2357.134 (64-разрядная версия)) в Mac OS X 10.10.4.

Есть ли способ, которым я могу поддерживать функциональность, когда < вход > виден во время его скрытия? или если не альтернативный маршрут, который я могу взять?


Я знаю похожие вопросы, ни одна из которых не затрагивает мою проблему, либо из-за того, что она слишком стар, а не на самом деле не использует Javascript или не подходит для конкретного сценария. Здесь хороший ответ для тех, у кого есть похожие, менее конкретные проблемы.

Ответы

Ответ 1

- Update -

Document.execCommand()

[1] До Firefox 41 необходимо, чтобы функция буфера обмена была включена в файле настроек user.js. Подробнее см. В кратком руководстве по настройкам Mozilla. Если команда не поддерживалась или не была включена, execCommand создавал исключение вместо того, чтобы возвращать false. В Firefox 41 и более поздних версиях функция буфера обмена включена по умолчанию в любом обработчике событий, который может всплывать окно (полунадежные скрипты).

Так как Firefox версии 41 теперь работает Document.execCommand(). Поэтому больше не нужно использовать резервную копию.


Поскольку браузеры, похоже, ведут себя по-разному, когда дело доходит до доступа к буферу, мне потребовалось некоторое время, чтобы обнять его вокруг.

Это очень похоже на ваше решение, но разница заключается в создании временного элемента и его заполнении с помощью ввода value. Таким образом, мы можем сохранить свойство ввода display равным none.

Существует также обходной путь для IE, который использует window.clipboardData.

Firefox не позволит мне получить доступ к буферу вообще. Поэтому мне пришлось добавить prompt, чтобы пользователи вручную копировали входное значение. Конечно, prompt является уродливым, но вы можете просто использовать модальное окно, которое будет делать то же самое.

Так как это кажется узловатым, я нахожусь на Win7 (64 бит) и тестировался в

Chrome - версия 43.0.2357.134 м

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>

Ответ 2

Здесь мое решение, которое не использует 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>

Ответ 3

Благодаря помощи @DavidDomain, я нашел несколько хакерский, но функциональный подход.

Во-первых, я переместил входной путь с экрана и изменил некоторые свойства, в результате получилось следующее:

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

display: ни один не был добавлен после следующих изменений в js

После этого комментарий @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 с помощью этого метода, что имеет смысл с точки зрения безопасности браузера, поскольку предоставление неоспоримого доступа к буферу будет несколько рискованным. Однако принятый подход имел тот же намеченный результат.

Ответ 4

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>

Ответ 5

Этот вопрос очень старый, поэтому у меня НОВЫЙ, менее устаревший ответ.

С помощью этого скрипта можно скопировать ваши данные. это намного меньше, чем прошлые

Все, что он делает, это скрывает ваш Input WAYYY от края экрана, следовательно, делает его скрытым. В то же время сохраняя возможность копировать его (в отличие от использования дисплея: нет;)

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>

Ответ 6

Что работает для меня было:

<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");
});

Ответ 7

Альтернативный обходной путь, который работает во всех браузерах, состоит в том, что вместо скрытия элемента вы можете установить его непрозрачность равной 0 с абсолютной позицией.

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

Ответ 9

Здесь простой, но хакерский ответ на этот вопрос, который, кажется, работает для меня. Вместо использования display: none; использовать этот:

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