На HTML-странице должно быть несколько фрагментов в тегах кода. Должна быть возможность скопировать код в буфер обмена нажатием кнопки. У меня есть рабочий код для одного тега кода, ссылка на который сделана с использованием идентификатора. Однако как изменить код JavaScript, чтобы копирование не зависело от предварительно определенного вручную идентификатора в теге кода. При нажатии кнопки копирования в буфер обмена для определенного фрагмента кода он должен автоматически копировать содержимое предполагаемого блока кода - при наличии многих других тегов кода с такой же кнопкой копирования в буфер обмена на странице. В моем примере показан один блок кода с предопределенным идентификатором. Как избежать идентификатора в JS-коде, чтобы он работал независимо?

function copy_text() {
  const str = document.getElementById("copy_code").innerText; const el = document.createElement("textarea");
  el.value = str; el.setAttribute("readonly", ""); el.style.position = "absolute";
  el.style.left = '-9999px'; document.body.appendChild(el);
  el.select(); document.execCommand("copy"); document.body.removeChild(el);
};
<code id="copy_code">some code 1<br>some code 2<br>some code 3</code>
<button onclick="copy_text()">Copy to clipboard</button>
2
jennab 9 Апр 2021 в 09:49

3 ответа

Лучший ответ

Вы можете передать this в вызов метода copy_text(), чтобы ваша функция точно знала, какая кнопка вызвала onclick event. Затем вы можете получить элементы его родительского контейнера, предполагая, что каждый блок code и его button находятся внутри родительского контейнера:

function copy_text(item) {
  const str = item.parentNode.querySelector('code').innerText;
  const el = document.createElement("textarea");
  el.value = str;
  el.setAttribute("readonly", "");
  el.style.position = "absolute";
  el.style.left = '-9999px';
  document.body.appendChild(el);
  el.select(); document.execCommand("copy");
  document.body.removeChild(el);
};
<div>
  <code>1<br>2<br>3</code>
  <button onclick="copy_text(this)">copy</button>
</div>

<div>
  <code>4<br>5<br>6</code>
  <button onclick="copy_text(this)">copy</button>
</div>

В случае, если каждый блок code и его button не находятся внутри какого-либо родительского контейнера и введены в HTML точно так же, как в вопросе, вы можете использовать

const str = item.previousElementSibling.innerText;

Вместо того

const str = item.parentNode.querySelector('code').innerText;
function copy_text(item) {
  const str = item.previousElementSibling.innerText;
  const el = document.createElement("textarea");
  el.value = str;
  el.setAttribute("readonly", "");
  el.style.position = "absolute";
  el.style.left = '-9999px';
  document.body.appendChild(el);
  el.select(); document.execCommand("copy");
  document.body.removeChild(el);
};
<code>1<br>2<br>3</code>
<button onclick="copy_text(this)">copy</button>
<br>
<code>4<br>5<br>6</code>
<button onclick="copy_text(this)">copy</button>
1
Ivan86 9 Апр 2021 в 07:17

Обратите внимание, что document.execCommand заменяется API буфера обмена < / а>.

Просто передайте id элемента, над которым он должен работать, обработчику копирования. Это сохраняет его независимость от структуры DOM и способа размещения кнопки и соответствующего блока кода в DOM относительно друг друга.

function copy_text(id) {
  if (!id) return;
  const code = document.getElementById(id);
  if (!code) return;
  if (navigator && navigator.clipboard) { // need to check because it's only available on https and localohost
    navigator.clipboard.writeText(code.innerHTML);
  }
};
<code id="foo">some code 1<br>some code 2<br>some code 3</code>
<button onclick="copy_text('foo')">Copy to clipboard</button>
<br/>
<code id="bar">some code 3<br>some code 4<br>some code 5</code>
<button onclick="copy_text('bar')">Copy to clipboard</button>
<textarea placeholder="Try to paste here to see if it works"></textarea>

Если структура DOM все равно исправлена ​​(за блоком кода всегда непосредственно следует кнопка копирования), вы можете полностью избавиться от идентификатора, используя element.previousElementSibling. В следующем примере я динамически генерирую элементы кнопки:

function copy_text(e) {
  const code = e.target.previousElementSibling;
  if (!code) return;
  if (navigator && navigator.clipboard) { // need to check because it's only available on https and localohost
    navigator.clipboard.writeText(code.innerHTML);
  }
}

document.addEventListener('DOMContentLoaded', function() {
  const snippets = document.querySelectorAll('.copyable-snippet');

  for (const snippet of snippets) {
    const button = document.createElement('button');
    button.type = 'button';
    button.textContent = 'Copy to clipboard';
    button.addEventListener('click', copy_text);
    snippet.parentElement.insertBefore(button, snippet.nextSibling);
  }
});
<code class="copyable-snippet">some code 1<br>some code 2<br>some code 3</code>
<code class="copyable-snippet">some code 3<br>some code 4<br>some code 5</code>
<textarea placeholder="Try to paste here to see if it works"></textarea>
1
connexo 9 Апр 2021 в 07:35

Во-первых, вам нужно использовать аргумент для передачи этого аргумента через функцию. Также используйте previousElementSibling для нацеливания на предыдущий элемент.

Я продублировал кнопку и скопировал для вас ресурс.

function copy_text(element) {
  const str = element.previousElementSibling.innerText; 
  const el = document.createElement("textarea");
  el.value = str; el.setAttribute("readonly", ""); el.style.position = "absolute";
  el.style.left = '-9999px'; document.body.appendChild(el);
  el.select(); document.execCommand("copy"); document.body.removeChild(el);
};
<code id="copy_code">some code 1<br>some code 2<br>some code 3</code>
<button onclick="copy_text(this)">Copy to clipboard</button>
<br>
<br>
<code id="copy_code_two">some code 4<br>some code 5<br>some code 6</code>
<button onclick="copy_text(this)">Copy to clipboard</button>
<br>
<br>
-2
s.kuznetsov 9 Апр 2021 в 07:47