Этот пост поможет добавить кнопку «Копировать» в элемент html. Он будет работать со всеми типами интерфейсных фреймворков (включая SSR и JAM-стек); основная идея будет такой же, но реализация может отличаться в зависимости от фреймворка.

Начнем с основной логики, то есть с копирования фрагмента текста в буфер обмена.

const copy = async (text) => await navigator.clipboard.writeText(text);

Вот и все !

Этот однострочный файл скопирует любой фрагмент текста с веб-страницы в буфер обмена. Это не ограничивается текстом, вы можете копировать любые произвольные данные, например. изображения в буфер обмена. Более подробную информацию, а также ограничения и поддержку браузера можно найти здесь.

Давайте посмотрим на некоторые варианты использования этого однострочника в реальных сценариях.

Скопируйте код с веб-страницы

Допустим, у вас есть веб-страница, содержащая много кода, и для каждого экземпляра требуется кнопка копирования.

Обычно код пишется внутри тега ‹code› тегом ‹pre›, что может закончиться примерно так.

<pre>
  <code>
	var message = "Hello world";
	console.log(message);
  </code>
</pre>

Чтобы разместить кнопку копирования на каждом теге ‹pre›, мы можем использовать следующую логику.

function enableCopy(selector = "pre", childSelector = "code", btnText = "Copy Me", btnTextSuccess = "Copied", activeClass = "--copy") {
    document.querySelectorAll(`${selector}:not(.${activeClass})`).forEach(node => {
 // create a "copy" button
 let copyBtn = document.createElement("button");
 copyBtn.innerText = btnText;
 // activeClass acts as flag so we don't add another copy button by  mistake
  copyBtn.classList.add(activeClass); 
  node.appendChild(copyBtn);
  copyBtn.addEventListener("click", async () => {
    // copy to clipboard
    if (navigator.clipboard) {
       let text = node.querySelector(childSelector).innerText;
       await navigator.clipboard.writeText();
    }
    // change text of button after copying
    copyBtn.innerText = btnTextSuccess;
    // change text back to normal after ### ms
    setTimeout(() => icon.innerText = btnText, 2000);
  })   
 })
}

Что он делает, так это вставляет ‹button› в каждый тег ‹pre›. При его нажатии требуемый текст копируется в буфер обмена.

Чтобы использовать его в нашем случае, просто вызовите метод без параметров; параметры по умолчанию будут работать.

Независимо от того, какой инструмент / библиотеку / фреймворк вы используете, этот подход будет работать.

Реализация как плагин VueJs

Поскольку я пришел из фона VueJs, я буду реализовывать ту же логику, что и плагин VueJS. Основная логика будет такой же, но лучший способ реализации может быть другим. В случае VueJS мы можем использовать плагины и хуки жизненного цикла, чтобы упростить процесс.

Это тот случай, когда шики использовалось для выделения кода. Однако в нем нет функции копировать код. То, как он обертывает код,

<pre class="shiki">
	<code>
		var message = "Hello world";
		console.log(message);
	</code>
</pre>

Чтобы добавить кнопку копирования в приведенный выше код, используя тот же подход, что и выше, плагин Vuejs написан следующим образом

// copyPlugin.js
const CopyPlugin = {
    // run this method when plugin installs
    install: function (Vue) {
				
	// create a Vue mixin
        Vue.mixin({
            // on each mounted lifecycle hook, run this code
            mounted: function () {
              // same function we used above
              enableCopy("pre.shiki"); 
            }
        })
    }
}
export default CopyPlugin;

Затем он импортируется и используется в main.js файле.

import Vue from "vue";
import CopyPlugin from "./copyPlugin";
Vue.use(CopyPlugin);

Это сделает работу. Единственным дополнительным моментом в этом подходе является обертка основной логики внутри системы плагинов Vuejs. То же самое относится к инструментам react, angular и любым другим. В конце концов, какой бы инструмент мы ни использовали, все сводится к обычным html, css и js.

Этот подход можно расширить, чтобы скопировать текст любого HTML-тега. И текст тоже может быть динамическим (с сервера). Например, вы можете проверить этот пост в блоге. Он такой же, как этот, разница в том, что фрагменты кода выделяются с помощью shiki, а кнопка копирования размещается тем же плагином Vuejs, который описан в этом посте.

Кстати, если вы хотите создавать красивые снимки кода, попробуйте RamroCode 👌