Javascript - копировать в буфер обмена без конкретного идентификатора в теге HTML

На 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>

почему бы вам просто не создать отдельные элементы <code> и <button> для каждого кода? или сопоставьте их каким-либо образом и просто добавьте номер индекса к id, например "copy_code_1", "copy_code_2" или что-то в этом роде

Sowam 09.04.2021 10:00
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
1
41
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете передать this в вызов метода copy_text(), чтобы ваша функция точно знала, какая кнопка активировала onclickevent. Затем вы можете получить элементы его родительского контейнера, предполагая, что каждый блок 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>

Спасибо @ Ivan86. Но что не так? Для обоих в вашем фрагменте 123 копируется в буфер обмена.

jennab 09.04.2021 10:15

@jennab извини, должно быть, я случайно удалил div

Ivan86 09.04.2021 10:16

@jennab Я отредактировал, чтобы включить фрагмент и для другого случая (элемент кода и кнопка не находятся внутри родительского контейнера).

Ivan86 09.04.2021 10:20

просто восхитительно. Благодарность!

jennab 09.04.2021 18:32

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

спасибо, но мне это понадобится без вручную определенного идентификатора

jennab 09.04.2021 10:17

@jennab, я исправил решение, указав разные ID для тегов <code>. Рад помочь.

s.kuznetsov 09.04.2021 14:51

замечательный. Благодарность!

jennab 09.04.2021 18:31

Обратите внимание, что 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>

Скажите, пожалуйста, почему ваш код у меня не работает?

s.kuznetsov 09.04.2021 14:56
navigator.clipboard доступен только в том случае, если страница работает в безопасном контексте (то есть https или localhost), как указано в источнике при проверке if (navigator && navigator.clipboard). В небезопасных ситуациях вам вообще не следует пытаться получить доступ к буферу обмена.
connexo 09.04.2021 15:12

Теперь понятно. Спасибо.

s.kuznetsov 09.04.2021 15:15

Другие вопросы по теме