איך להדביק תמונות

הדרך המודרנית

שימוש ב-Async Clipboard API

כדי לקרוא תמונות מלוח העריכה של המשתמש באופן פרוגרמטי, כלומר אחרי לחיצה על לחצן, אפשר להשתמש בשיטה read() של Async Clipboard 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);
  }
});

Browser Support

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 127.
  • Safari: 13.1.

Source

הדרך הקלאסית

האזנה לאירוע paste

הדרך הקלאסית להדבקת תמונות היא באמצעות Clipboard 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.
    }
  }
});

Browser Support

  • Chrome: 66.
  • Edge: 79.
  • Firefox: 63.
  • Safari: 13.1.

Source

שיפור הדרגתי

בדפדפנים שלא תומכים ב-Async Clipboard API, אי אפשר לגשת ללוח העריכה של המשתמש באופן פרוגרמטי (לדוגמה, בלחיצה על לחצן). לכן, כדי לגשת ללוח העריכה של משתמש באירוע paste, אפשר להשתמש ב-Async Clipboard API ולחזור ל-Clipboard 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.
      }
    }
  }
});

קריאה נוספת

  • Clipboard 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);
};