Хотите скопировать изображение? Взгляните на API буфера обмена

внешний интерфейс
Хотите скопировать изображение? Взгляните на API буфера обмена

на письмеВ этой 29,7-килобайтной JS-библиотеке буфера обмена есть что-то!После этой статьи я получил два вопроса от друзей:

1.clipboard.jsПомимо копирования текста, может ли эта библиотека копировать изображения?

2.clipboard.jsЭта библиотека зависит отdocument.execCommandAPI устарел, что мне делать в будущем?

(Источник изображения:developer.Mozilla.org/this-cn/docs/…

Далее в этой статье основное внимание будет уделено двум вышеуказанным вопросам, но прежде чем рассматривать первый вопрос, давайте кратко представимбуфер обмена📋.

Буфер обмена (англ. clipboard), иногда называемый буфером обмена, альбомом для вырезок, альбомом для вырезок. Это программная функция, обычно предоставляемая операционной системой.Используется для кратковременного хранения данных и передачи данных между документами или приложениями с помощью операций копирования и вставки.. Это одна из наиболее часто используемых функций в среде графического пользовательского интерфейса (GUI) и обычно реализуется как анонимный временный буфер данных, к которому может обращаться большинство или все программы в среде с помощью интерфейса программирования. -- Википедия

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

пониматьбуфер обменаПосле концепции и роли 📋 давайте рассмотрим первый вопрос:clipboard.jsПомимо копирования текста, может ли эта библиотека копировать изображения?

Следуйте «Дороге полного стека», чтобы прочитать 4 бесплатные электронные книги (в общей сложности более 21 000 загрузок) и 50 учебных пособий «Повторное изучение TS» от брата Абао.

1. Может ли clipboard.js копировать изображения?

clipboard.jsэтотекстJS-библиотека для копирования в буфер обмена. Никакого Flash, никаких фреймворков, только сжатие gzip3kb.

(Источник изображения:буфер обмена — .com/#example-spec…

когда ты видишь"Современный подход к копированию текста в буфер обмена"Это описание, вы уже знаете ответ. Так какова реальная ситуация? Проверим вручную. существуетВ этой 29,7-килобайтной JS-библиотеке буфера обмена есть что-то!В этой статье брат Абао рассказывает, как создать экземплярClipboardJSобъект, вы можете пройтиoptionsобъектtargetсвойство, чтобы установить цель копии:

// https://github.com/zenorocha/clipboard.js/blob/master/demo/function-target.html
let clipboard = new ClipboardJS('.btn', {
  target: function() {
    return document.querySelector('div');
  }
});

использоватьclipboard.jsС помощью этой функции мы можем определить следующую структуру HTML:

<div id="container">
   <img src="http://cdn.semlinker.com/abao.png" width="80" height="80"/>
   <p>大家好,我是阿宝哥</p>
</div>
<button class="btn">复制</button>

а затем создать экземплярClipboardJSЦель репликации устанавливается, когда объект#containerэлемент:

const clipboard = new ClipboardJS(".btn", {
  target: function () {
    return document.querySelector("#container");
  }
});

После этого кликаем на страницукопироватькнопка, соответствующий эффект показан на следующем рисунке:

Наблюдая за изображением выше, мы видим, что изображения и текст на странице были скопированы. Для текста все должно быть предельно ясно. А для образов что именно тиражируется? Как мы можем получить скопированный контент? Для этой задачи мы можем использоватьHTMLElementна объектеonpasteатрибут или элемент прослушивателяpasteмероприятие.

Здесь мы устанавливаемdocumentобъектonpasteдля печати объекта события, соответствующего событию вставки:

document.onpaste = function (e) {
  console.dir(e);
}

когда мы нажимаемкопироватькнопку, а затем выполнить на страницевставитьПосле операции консоль выводит следующее:

Как видно из приведенного выше рисунка,ClipboardEventобъект содержитclipboardDataсвойство, содержащее данные, связанные с буфером обмена. подробно проанализированыclipboardDataсвойства, мы обнаруживаем, что скопированное изображение и обычный текст инкапсулированы какDataTransferItemобъект.

Для облегчения анализаDataTransferItemОбъект, Брат Бао повторно обновленdocumentобъектonpasteАтрибуты:

На приведенном выше рисунке мы ясно видимDataTransferItemобъект содержитkindа такжеtypeАтрибуты используются для представления типа элемента данных (строка или файл) и соответствующего MIME-типа данных. использоватьDataTransferItemпредоставленный объектgetAsStringМетод, мы можем получить данные в объекте:

Я полагаю, что после прочтения приведенных выше выходных результатов друзья очень хорошо узнают ответ на первый вопрос. Итак, если вы хотите скопировать изображение, как вам это сделать? Фактически ответ на этот вопрос совпадает с ответом на второй вопрос, поставленный малым партнером.ClipboardAPI для реализации проблемы и решения копирования изображенийdocument.execCommandПроблемы с API устарели.

Далее наша цель реализовать функцию копирования изображений, т.к. нам нужно использоватьClipboardAPI, поэтому брат Абао первым представит API.

2. Введение в API буфера обмена

ClipboardИнтерфейс реализованClipboardAPI, если пользователь предоставляет соответствующие разрешения, предоставляет доступ для чтения и записи к системному буферу обмена. В веб-приложении API буфера обмена можно использовать для реализации функций вырезания, копирования и вставки. Этот API используется для заменыdocument.execCommandAPI для реализации операций с буфером обмена.

В реальном проекте нам не нужно вручную создаватьClipboardобъект, но черезnavigator.clipboardполучитьClipboardОбъект:

в полученииClipboardПосле объекта мы можем использовать API, предоставляемый объектом, для доступа к буферу обмена, например:

navigator.clipboard.readText().then(
  clipText => document.querySelector(".editor").innerText = clipText);

Приведенный выше код будет включать в себя HTML.editorСодержимое первого элемента класса заменяется содержимым буфера обмена. Если буфер обмена пуст или не содержит текста, содержимое элемента будет очищено. Это связано с тем, что когда буфер обмена пуст или не содержит текста,readTextМетод возвращает пустую строку.

продолжать знакомитьClipboardПеред API давайте посмотримNavigator API: clipboardСовместимость:

(Источник изображения:потрите newser.com/madonna-api_thatv…

API асинхронного буфера обмена — это относительно новый API, и браузеры все еще постепенно внедряют его. Из-за потенциальных проблем с безопасностью и технической сложности большинство браузеров постепенно интегрируют этот API. Для расширений браузера вы можете запросить разрешения clipboardRead и clipboardWrite для использования clipboard.readText() и clipboard.writeText().

Хорошо, дальше брат Бао продемонстрирует, как им пользоваться.clipboardAPI, предоставляемый объектом для работы с буфером обмена, рабочая среда следующего примера:Chrome 87.0.4280.88.

3. Запишите данные в буфер обмена

3.1 writeText()

writeTextМетод может записать указанную строку в системный буфер обмена, после вызова этого метода он вернет объект Promise:

<button onclick="copyPageUrl()">拷贝当前页面地址</button>
<script>
   async function copyPageUrl() {
     try {
       await navigator.clipboard.writeText(location.href);
       console.log("页面地址已经被拷贝到剪贴板中");
     } catch (err) {
       console.error("页面地址拷贝失败: ", err);
     }
  }
</script>

Для приведенного выше кода, когда пользователь нажимаетСкопируйте адрес текущей страницыПри нажатии кнопки адрес текущей страницы будет скопирован в буфер обмена.

3.2 write()

writeПомимо поддержки текстовых данных, метод также поддерживает запись данных изображения в буфер обмена.После вызова этого метода будет возвращен объект Promise.

<button onclick="copyPageUrl()">拷贝当前页面地址</button>
<script>
   async function copyPageUrl() {
     const text = new Blob([location.href], {type: 'text/plain'});
     try {
       await navigator.clipboard.write(
         new ClipboardItem({
           "text/plain": text,
         }),
       );
       console.log("页面地址已经被拷贝到剪贴板中");
     } catch (err) {
       console.error("页面地址拷贝失败: ", err);
     }
  }
</script>

В приведенном выше коде мы сначала передаемBlobAPI создает объект Blob, а затем использует этот объект Blob для созданияClipboardItemобъект и, наконец, черезwriteспособ записи данных в буфер обмена. После знакомства с тем, как записывать данные в буфер обмена, давайте познакомимся с тем, как читать данные из буфера обмена.

Для тех, кто интересуется Blob API, вы можете прочитатьКапли, о которых вы не зналиЭта статья.

В-четвертых, прочитать данные из буфера обмена

4.1 readText()

readTextМетод используется для чтения текстового содержимого буфера обмена, после вызова этого метода он вернет объект Promise:

<button onclick="getClipboardContents()">读取剪贴板中的文本</button>
<script>
   async function getClipboardContents() {
     try {
       const text = await navigator.clipboard.readText();
       console.log("已读取剪贴板中的内容:", text);
     } catch (err) {
       console.error("读取剪贴板内容失败: ", err);
     }
   }
</script>

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

4.2 read()

readПомимо чтения текстовых данных, метод также поддерживает чтение данных изображений из буфера обмена, после вызова этого метода он вернет объект Promise:

<button onclick="getClipboardContents()">读取剪贴板中的内容</button>
<script>
async function getClipboardContents() {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      for (const type of clipboardItem.types) {
        const blob = await clipboardItem.getType(type);
        console.log("已读取剪贴板中的内容:", await blob.text());
      }
    }
  } catch (err) {
      console.error("读取剪贴板内容失败: ", err);
    }
  }
</script>

Для приведенного выше кода, когда пользователь нажимаетПрочитать содержимое буфера обменакнопку, он начнет читать содержимое буфера обмена. сюдаclipboard4 API-интерфейса, задействованные в объекте, были представлены Brother Abao.Наконец, давайте посмотрим, как реализовать функцию копирования изображений.

В-пятых, реализовать функцию копирования изображений

В последнем примере Brother A Bao реализует основную функцию пошагового копирования изображений.Помимо копирования изображений, он также будет поддерживать одновременное копирование текста. Прежде чем рассматривать конкретный код, давайте взглянем на фактический эффект:

На веб-странице, соответствующей рисунку выше, мы сначала нажимаемкопироватькнопка, и изображение и текст будут выбраны. После этого нажимаемвставитькнопка, консоль выведет фактический контент, считанный из буфера обмена. Прежде чем анализировать конкретную реализацию, давайте взглянем на соответствующую структуру страницы:

<div id="container">
   <img src="http://cdn.semlinker.com/abao.png" width="80" height="80" />
   <p>大家好,我是阿宝哥</p>
</div>
<button onclick="writeDataToClipboard()">复制</button>
<button onclick="readDataFromClipboard()">粘贴</button>

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

5.1 Запрос разрешения на запись в буфер обмена

По умолчанию текущей активной странице автоматически предоставляется доступ для записи в буфер обмена. Из соображений безопасности здесь мы по-прежнему активно запрашиваем у пользователя разрешение на запись в буфер обмена:

async function askWritePermission() {
  try {
    const { state } = await navigator.permissions.query({
      name: "clipboard-write",
    });
      return state === "granted";
  } catch (error) {
      return false;
  }
}

5.2 Запись изображений и обычных текстовых данных в буфер обмена

Чтобы записать данные изображения в буфер обмена, нам нужно использоватьnavigator.clipboardпредоставленный объектwriteметод. Если вы хотите записать данные изображения, нам нужно получить изображение, соответствующее объекту Blob, где мы можемfetchAPI получает из сети объект ответа, соответствующий изображению, и преобразует его в объект Blob. Конкретная реализация выглядит следующим образом:

async function createImageBlob(url) {
  const response = await fetch(url);
  return await response.blob();
}

Для обычного текста просто используйте API Blob, описанный ранее, чтобы преобразовать обычный текст в объект Blob:

function createTextBlob(text) {
  return new Blob([text], { type: "text/plain" });
}

После создания объектов Blob, соответствующих изображениям и обычному тексту, мы можем использовать их для созданияClipboardItemобъект, а затем вызватьwriteМетод записывает эти данные в буфер обмена, и соответствующий код выглядит следующим образом:

async function writeDataToClipboard() {
  if (askWritePermission()) {
    if (navigator.clipboard && navigator.clipboard.write) {
        const textBlob = createTextBlob("大家好,我是阿宝哥");
        const imageBlob = await createImageBlob(
          "http://cdn.semlinker.com/abao.png"
        );
        try {
          const item = new ClipboardItem({
            [textBlob.type]: textBlob,
            [imageBlob.type]: imageBlob,
          });
          select(document.querySelector("#container"));
          await navigator.clipboard.write([item]);
          console.log("文本和图像复制成功");
        } catch (error) {
          console.error("文本和图像复制失败", error);
        }
      }
   }
}

В приведенном выше кодеselectметод, который используется для достижения эффекта выделения, и соответствующий код выглядит следующим образом:

function select(element) {
  const selection = window.getSelection();
  const range = document.createRange();
  range.selectNodeContents(element);
  selection.removeAllRanges();
  selection.addRange(range);
}

пройти черезwriteDataToClipboardмы записали изображение и обычные текстовые данные в буфер обмена. Давайте использоватьnavigator.clipboardпредоставленный объектreadспособ чтения записанных данных. Если вам нужно прочитать данные буфера обмена, вам нужно попросить пользователяclipboard-readразрешения.

5.3 Запрос разрешения на чтение буфера обмена

Здесь мы определяемaskReadPermissionфункция для запроса разрешения на чтение буфера обмена у пользователя:

async function askReadPermission() {
  try {
    const { state } = await navigator.permissions.query({
      name: "clipboard-read",
    });
    return state === "granted";
  } catch (error) {
    return false;
  }
}

при звонкеaskReadPermissionПосле метода текущему пользователю будет предложено прочитать разрешение буфера обмена, и соответствующий эффект показан на следующем рисунке:

5.4 Чтение данных, записанных в буфер обмена

созданныйaskReadPermissionфункцию, мы можем использовать введенную ранееnavigator.clipboard.readспособ чтения данных из буфера обмена:

async function readDataFromClipboard() {
  if (askReadPermission()) {
    if (navigator.clipboard && navigator.clipboard.read) {
      try {
        const clipboardItems = await navigator.clipboard.read();
        for (const clipboardItem of clipboardItems) {
          console.dir(clipboardItem);
          for (const type of clipboardItem.types) {
            const blob = await clipboardItem.getType(type);
            console.log("已读取剪贴板中的内容:", await blob.text());
          }
        }
      } catch (err) {
         console.error("读取剪贴板内容失败: ", err);
      }
     }
   }
}

На самом деле, помимо щелчкавставитьВ дополнение к кнопке, мы также можем контролироватьpasteсобытие для чтения данных из буфера обмена. Следует отметить, что если текущий браузер не поддерживает асинхронныйClipboardAPI, мы можем передатьclipboardData.getDataметод чтения текстовых данных из буфера обмена:

document.addEventListener('paste', async (e) => {
  e.preventDefault();
  let text;
  if (navigator.clipboard) {
    text = await navigator.clipboard.readText();
  } else {
    text = e.clipboardData.getData('text/plain');
  }
  console.log('已获取的文本数据: ', text);
});

А для данных изображения их можно прочитать следующими способами:

const IMAGE_MIME_REGEX = /^image\/(p?jpeg|gif|png)$/i;

document.addEventListener("paste", async (e) => {
  e.preventDefault();
  if (navigator.clipboard) {
    let clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
       for (const type of clipboardItem.types) {
         if (IMAGE_MIME_REGEX.test(type)) {
           const blob = await clipboardItem.getType(type);
           loadImage(blob);
           return;
         }
        }
     }
   } else {
       const items = e.clipboardData.items;
       for (let i = 0; i < items.length; i++) {
         if (IMAGE_MIME_REGEX.test(items[i].type)) {
         loadImage(items[i].getAsFile());
         return;
       }
    }
  }
});

в приведенном выше кодеloadImageМетод используется для вставки скопированного изображения в выделенную область текущего выделения, соответствующий код выглядит следующим образом:

function loadImage(file) {
  const reader = new FileReader();
  reader.onload = function (e) {
    let img = document.createElement("img");
    img.src = e.target.result;

    let range = window.getSelection().getRangeAt(0);
    range.deleteContents();
    range.insertNode(img);
  };
  reader.readAsDataURL(file);
}

В предыдущем коде мы слушалиdocumentобъектpasteмероприятие. В дополнение к этому событию, общие события, связанные с буфером обмена,copyа такжеcutмероприятие. Из-за ограниченного места, брат Абао не будет вводить его дальше.Заинтересованные друзья могут сами прочитать соответствующую информацию. Хорошо, пока эта статья закончена, я надеюсь, что после прочтения этой статьи у вас будет хорошее представление об асинхронныхClipboardУ вас будет некоторое понимание API, и есть места, которые не совсем написаны. Вы можете общаться с братом Абао в любое время.

Следуйте «Дороге развития полного стека», чтобы прочитать 4 бесплатные электронные книги (в общей сложности более 21 000 загрузок) и 9 руководств по анализу исходного кода, изначально написанных братом А. Бао.

6. Справочные ресурсы