В Chrome 66 добавлен API асинхронного буфера обмена

внешний интерфейс API Chrome Promise
В Chrome 66 добавлен API асинхронного буфера обмена

Искусство:Unblocking Clipboard Access

Последние несколько лет мы могли использовать толькоdocument.execCommandдля работы с буфером обмена. Однако это манипулирование буфером обмена является синхронным и может только читать и записывать в DOM.

Chrome 66 теперь поддерживает новыйAsync Clipboard API, так какexecCommandальтернативы.

Новый API асинхронного буфера обмена также может использовать Promises для упрощения событий буфера обмена и использовать их с API Drag-&-Drop.

Демонстрационное видео:zhuanlan.zhihu.com/p/34698155

Копировать: записать текст в буфер обмена

writeText()Вы можете записать текст в буфер обмена.writeText()является асинхронным, он возвращает обещание:

navigator.clipboard.writeText('要复制的文本')
  .then(() => {
    console.log('文本已经成功复制到剪切板');
  })
  .catch(err => {
    // This can happen if the user denies clipboard permissions:
    // 如果用户没有授权,则抛出异常
    console.error('无法复制此文本:', err);
  });

также можно использоватьасинхронная функцияизasyncа такжеawait:

async function copyPageUrl() {
  try {
    await navigator.clipboard.writeText(location.href);
    console.log('Page URL copied to clipboard');
  } catch (err) {
    console.error('Failed to copy: ', err);
  }
}

Вставить: прочитать текст из буфера обмена

Как и в случае копирования, это можно сделать, вызвавreadText()Прочитайте текст из буфера обмена, эта функция также возвращает Promise:

navigator.clipboard.readText()
  .then(text => {
    console.log('Pasted content: ', text);
  })
  .catch(err => {
    console.error('Failed to read clipboard contents: ', err);
  });

Для согласованности вот эквивалентная асинхронная функция:

async function getClipboardContents() {
  try {
    const text = await navigator.clipboard.readText();
    console.log('Pasted content: ', text);
  } catch (err) {
    console.error('Failed to read clipboard contents: ', err);
  }
}

Обработка событий вставки

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

document.addEventListener('paste', event => {
  event.preventDefault();
  navigator.clipboard.readText().then(text => {
    console.log('Pasted text: ', text);
  });
});

Безопасность и разрешения

Доступ к буферу обмена всегда создавал проблемы безопасности для браузеров. Без надлежащих разрешений страница может незаметно скопировать весь вредоносный контент в буфер обмена пользователя, что приведет к катастрофическим результатам при вставке. Представьте себе веб-страницу, молча скопированнуюrm -rf /илираспаковать образ бомбыВ буфер обмена.

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

Как и многие новые API,navigator.clipboardПоддерживаются только страницы, обслуживаемые через HTTPS. Во избежание злоупотреблений доступ к буферу обмена разрешен только тогда, когда страница находится на активной вкладке. Страницы на активной вкладке могут записывать в буфер обмена без запроса разрешения, но чтение из буфера обмена всегда требует разрешения.

Для упрощения были добавлены два новых разрешения для копирования и вставки.Permissions APIсередина. Разрешение на запись в буфер обмена автоматически предоставляется странице, когда страница находится на активной вкладке. Когда вы читаете данные из буфера обмена, вы должны запрашивать разрешение на чтение буфера обмена.

{ name: 'clipboard-read' }
{ name: 'clipboard-write' }
prompt

Как и во всем остальном, используя Permissions API, вы можете проверить, есть ли у вашего приложения разрешение на взаимодействие с буфером обмена:

navigator.permissions.query({
  name: 'clipboard-read'
}).then(permissionStatus => {
  // permissionStatus.state 的值是 'granted'、'denied'、'prompt':
  console.log(permissionStatus.state);

  // 监听权限状态改变事件
  permissionStatus.onchange = () => {
    console.log(permissionStatus.state);
  };
});

Вот где «асинхронная» часть API буфера обмена действительно пригодится: при попытке чтения или записи данных буфера обмена у пользователя автоматически запрашивается разрешение (если оно еще не предоставлено). Поскольку API основан на обещаниях, если пользователь отклоняет разрешения буфера обмена, обещание будет отклонено, поэтому страница может ответить соответствующим образом.

Поскольку Chrome разрешает доступ к буферу обмена только тогда, когда страница является текущей активной вкладкой, если вы вставляете непосредственно в DevTools, вы обнаружите, что некоторые из приведенных здесь примеров работают неправильно, потому что в этот момент сама DevTools является активной вкладкой (вкладка страница не является активной вкладкой) Tab). Есть хитрость: нам нужно отложить доступ к буферу обмена с помощью setTimeout, а затем быстро щелкнуть внутри страницы, чтобы получить фокус страницы перед вызовом функции:

setTimeout(async () => {
  const text = await navigator.clipboard.readText();
  console.log(text);
}, 2000);

рассмотрение

До введения асинхронного API буфера обмена у нас было сочетание различных реализаций копирования и вставки в веб-браузерах.

В большинстве браузеров вы можете использоватьdocument.execCommand('copy')и запустить собственное копирование и вставку браузераdocument.execCommand('paste'). Если копируемый текст представляет собой строку, которой нет в DOM, мы должны вставить ее в DOM и выбрать:

button.addEventListener('click', e => {
  const input = document.createElement('input');
  document.body.appendChild(input);
  input.value = text;
  input.focus();
  input.select();
  const result = document.execCommand('copy');
  if (result === 'unsuccessful') {
    console.error('Failed to copy text.');
  }
})

Опять же, вот как вы можете обрабатывать вставленный контент в браузерах, которые не поддерживают новый API асинхронного буфера обмена:

document.addEventListener('paste', e => {
  const text = e.clipboardData.getData('text/plain');
  console.log('Got pasted text: ', text);
})

В Internet Explorer мы также можем передатьwindow.clipboardDataДоступ к буферу обмена. Если доступ осуществляется жестом пользователя (например, касанием) -Запросить разрешение ответственным образомчасть - то запрос разрешения не отображается.

обнаружение и откат

При поддержке всех браузеров рекомендуется использовать обнаружение функций, чтобы воспользоваться преимуществами асинхронного буфера обмена. Вы можете проверить поnavigator.clipboardЧтобы обнаружить поддержку API асинхронного буфера обмена:

document.addEventListener('paste', async e => {
  let text;
  if (navigator.clipboard) {
    text = await navigator.clipboard.readText()
  }
  else {
    text = e.clipboardData.getData('text/plain');
  }
  console.log('Got pasted text: ', text);
});

Что дальше для API асинхронного буфера обмена?

Как вы могли заметить, в этой статье рассматриваются толькоnavigator.clipboardчасть текста. В спецификации больше дженериковread()а такжеwrite()методы, но они создают дополнительную сложность реализации и проблемы с безопасностью (помните эти бомбы с изображениями?). В настоящее время Chrome внедряет более простую текстовую часть API.

Больше информации