วิธีวางรูปภาพ

วิธีที่ทันสมัย

การใช้ 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 event อย่างไรก็ตาม วิธีนี้มีข้อจำกัด เช่น การวางข้อมูลจำนวนมากอาจบล็อกหน้าเว็บเนื่องจากเป็นแบบซิงโครนัส

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