Современный способ
Использование API асинхронного буфера обмена
Для программного чтения изображений из буфера обмена пользователя, то есть после нажатия кнопки, можно использовать метод read() из API асинхронного чтения из буфера обмена . Если разрешение на чтение из буфера обмена еще не предоставлено, вызов ` navigator.clipboard.read() запросит его при первом вызове метода.
const pasteButton = document.querySelector('#paste-button');
pasteButton.addEventListener('click', async () => {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
const imageTypes = clipboardItem.types.find(type => type.startsWith('image/'))
for (const imageType of imageTypes) {
const blob = await clipboardItem.getType(imageType);
// Do something with the image blob.
}
}
} catch (err) {
console.error(err.name, err.message);
}
});
Классический способ
Слушайте событие paste
Классический способ вставки изображений — использование (синхронного) API буфера обмена , который предоставляет доступ к полю clipboardData внутри события Document: paste . Однако этот метод имеет ограничения, например, поскольку он синхронный, вставка больших объемов данных может заблокировать страницу.
document.addEventListener('paste', async (e) => {
e.preventDefault();
for (const clipboardItem of e.clipboardData.files) {
if (clipboardItem.type.startsWith('image/')) {
// Do something with the image file.
}
}
});
Прогрессивное улучшение
Для браузеров, не поддерживающих асинхронный API буфера обмена, программный доступ к буферу обмена пользователя (например, при нажатии кнопки) невозможен. Таким образом, для доступа к буферу обмена пользователя при paste можно использовать асинхронный API буфера обмена, а в качестве запасного варианта использовать (синхронный) API буфера обмена.
Объекты ClipboardItem получаемые из navigator.clipboard.read имеют поле types , представляющее собой массив, а объекты File , получаемые из event.clipboardData.files , имеют поле type , представляющее собой строку. Вы можете условно проверять каждое из полей type или types на наличие изображений в буфере обмена:
document.addEventListener('paste', async (e) => {
e.preventDefault();
const clipboardItems = typeof navigator?.clipboard?.read === 'function' ? await navigator.clipboard.read() : e.clipboardData.files;
for (const clipboardItem of clipboardItems) {
let blob;
if (clipboardItem.type?.startsWith('image/')) {
// For files from `e.clipboardData.files`.
blob = clipboardItem
// Do something with the blob.
} else {
// For files from `navigator.clipboard.read()`.
const imageTypes = clipboardItem.types?.filter(type => type.startsWith('image/'))
for (const imageType of imageTypes) {
blob = await clipboardItem.getType(imageType);
// Do something with the blob.
}
}
}
});
Дополнительная информация
- API буфера обмена на MDN
- Разблокировка доступа к буферу обмена на web.dev
Демо
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎉</text></svg>"
/>
<title>How to paste images</title>
</head>
<body>
<h1>How to paste images</h1>
<p>Hit <kbd>⌘</kbd> + <kbd>v</kbd> (for macOS) or <kbd>ctrl</kbd> + <kbd>v</kbd>
(for other operating systems) to paste images anywhere in this page.
</p>
</body>
</html>CSS
:root {
color-scheme: dark light;
}
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 1rem;
font-family: system-ui, sans-serif;
}
button {
display: block;
}
JS
document.addEventListener('paste', async (e) => {
e.preventDefault();
const clipboardItems = typeof navigator?.clipboard?.read === 'function' ? await navigator.clipboard.read() : e.clipboardData.files;
for (const clipboardItem of clipboardItems) {
let blob;
if (clipboardItem.type?.startsWith('image/')) {
// For files from `e.clipboardData.files`.
blob = clipboardItem
// Do something with the blob.
appendImage(blob);
} else {
// For files from `navigator.clipboard.read()`.
const imageTypes = clipboardItem.types?.filter(type => type.startsWith('image/'))
for (const imageType of imageTypes) {
blob = await clipboardItem.getType(imageType);
// Do something with the blob.
appendImage(blob);
}
}
}
});
const appendImage = (blob) => {
const img = document.createElement('img');
img.src = URL.createObjectURL(blob);
document.body.append(img);
};