Clipboard: read() 方法

Baseline 2024 *
新推出

自 2024 年 6 月起,此功能已在最新的裝置和瀏覽器版本中可用。此功能可能不適用於較舊的裝置或瀏覽器。

* 此特性的某些部分可能存在不同級別的支援。

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

Clipboard 介面的 read() 方法請求複製剪貼簿的內容,並使用返回的 Promise 來處理資料。

理論上,該方法可以返回任意資料(與只能返回文字的 readText() 不同)。瀏覽器通常支援讀取文字、HTML 和 PNG 影像資料。

語法

js
read()
read(formats)

引數

formats 可選

一個可選物件,具有以下屬性:

unsanitized 可選

一個包含 MIME 型別的字串 Array,這些 MIME 型別的資料格式在從剪貼簿讀取時將不被清理。

某些瀏覽器在讀取剪貼簿資料時可能會對其進行清理,以防止惡意內容被貼上到文件中。例如,Chrome(及其他基於 Chromium 的瀏覽器)會透過移除 <script> 標籤和其他潛在危險內容來清理 HTML 資料。使用 unsanitized 陣列可以指定一組不應被清理的 MIME 型別。

返回值

一個 Promise,它將解析為一個 ClipboardItem 物件陣列,其中包含剪貼簿的內容。

異常

NotAllowedError DOMException

如果在剪貼簿讀取過程中不允許,則丟擲此異常。

安全注意事項

剪貼簿讀取只能在 安全上下文 中進行。

其他安全要求已在 API 概述主題的 安全注意事項 部分介紹。

示例

從剪貼簿讀取影像資料

此示例使用 read() 方法從剪貼簿讀取影像資料,並將其貼上到 <img> 元素中。

HTML

html
<img id="source" src="butterfly.jpg" alt="A butterfly" />
<img id="destination" />
<button id="reload" type="button">Reload</button>
<p id="log"></p>

CSS

css
img {
  height: 100px;
  width: 100px;
  margin: 0 1rem;
  border: 1px solid black;
}
#reload {
  display: block;
  margin: 0 1rem;
}

JavaScript

此程式碼提供了一種機制,用於將任何錯誤記錄到 id 為 log 的元素中。

js
const logElement = document.querySelector("#log");
function log(text) {
  logElement.innerText = `Error: ${text}`;
}

當按下“過載”按鈕時,我們還添加了程式碼來過載和清除示例。

js
const reload = document.querySelector("#reload");

reload.addEventListener("click", () => {
  window.location.reload(true);
});

其餘程式碼會在目標元素被點選時讀取剪貼簿,並將影像資料複製到 destinationImage 元素中。如果無法使用 read() 方法,或者剪貼簿不包含 PNG 格式的資料,它將記錄一個錯誤。

js
const destinationImage = document.querySelector("#destination");
destinationImage.addEventListener("click", pasteImage);

async function pasteImage() {
  try {
    const clipboardContents = await navigator.clipboard.read();
    for (const item of clipboardContents) {
      if (!item.types.includes("image/png")) {
        throw new Error("Clipboard does not contain PNG image data.");
      }
      const blob = await item.getType("image/png");
      destinationImage.src = URL.createObjectURL(blob);
    }
  } catch (error) {
    log(error.message);
  }
}

結果

透過右鍵單擊左側的蝴蝶影像並從上下文選單中選擇“複製影像”來複制它。然後單擊右側的空白框。該示例將從剪貼簿獲取影像資料,並在空白框中顯示影像。

注意: 如果出現提示,請授予許可權以貼上影像。

從剪貼簿讀取資料

此示例使用 read() 方法從剪貼簿讀取資料,並記錄儲存在剪貼簿中的任何資料。

這與前一個版本不同,因為它將顯示文字、HTML 和影像 ClipboardItem 物件(而不是僅影像)。

HTML

html
<img id="source_jpg" src="butterfly.jpg" alt="JPG butterfly image" />
<div id="destination">Click here to copy clipboard data.</div>
<button id="reload" type="button">Reload</button>
<p id="log"></p>

CSS

css
img {
  height: 100px;
  width: 100px;
  margin: 0 1rem;
  border: 1px solid black;
}

#destination {
  min-height: 300px;
  min-width: 90%;
  margin: 0 1rem;
  border: 1px solid black;
}

#reload {
  display: block;
  margin: 0 1rem;
}

JavaScript

此程式碼提供了一種機制,用於將任何錯誤記錄到 id 為 log 的元素中。

js
const logElement = document.querySelector("#log");
function log(text) {
  logElement.innerText = `Error: ${text}`;
}

當按下“過載”按鈕時,我們還添加了程式碼來過載和清除示例。

js
const reload = document.querySelector("#reload");

reload.addEventListener("click", () => {
  window.location.reload(true);
});

其餘程式碼會在目標元素被點選時讀取剪貼簿,並顯示每個 ClipboardItem 元素及其 MIME 型別。如果無法使用 read() 方法,或者剪貼簿包含任何其他 MIME 型別,它將記錄一個錯誤。

js
const destinationDiv = document.querySelector("#destination");
destinationDiv.addEventListener("click", pasteData);

async function pasteData() {
  destinationDiv.innerText = ""; // Clear inner text
  try {
    const clipboardContents = await navigator.clipboard.read();
    for (const item of clipboardContents) {
      for (const mimeType of item.types) {
        const mimeTypeElement = document.createElement("p");
        mimeTypeElement.innerText = `MIME type: ${mimeType}`;
        destinationDiv.appendChild(mimeTypeElement);
        if (mimeType === "image/png") {
          const pngImage = new Image();
          pngImage.alt = "PNG image from clipboard";
          const blob = await item.getType("image/png");
          pngImage.src = URL.createObjectURL(blob);
          destinationDiv.appendChild(pngImage);
        } else if (mimeType === "text/html") {
          const blob = await item.getType("text/html");
          const blobText = await blob.text();
          const clipHTML = document.createElement("pre");
          clipHTML.innerText = blobText;
          destinationDiv.appendChild(clipHTML);
        } else if (mimeType === "text/plain") {
          const blob = await item.getType("text/plain");
          const blobText = await blob.text();
          const clipPlain = document.createElement("pre");
          clipPlain.innerText = blobText;
          destinationDiv.appendChild(clipPlain);
        } else {
          throw new Error(`${mimeType} not supported.`);
        }
      }
    }
  } catch (error) {
    log(error.message);
  }
}

結果

複製下面的某些文字或蝴蝶(JPG)影像(要複製影像,請右鍵單擊它們,然後從上下文選單中選擇“複製影像”)。選擇下面的指示框,將此資訊從剪貼簿貼上到該框中。

注意

  • 即使蝴蝶影像是 JPG 檔案,從剪貼簿讀取時它也是 PNG 格式。
  • 如果出現提示,您將需要授予許可權才能貼上影像。
  • 這在 Chromium 瀏覽器上可能不起作用,因為示例框架未獲得 Permissions-Policyclipboard-readclipboard-write 許可權(Chromium 瀏覽器需要)。

從剪貼簿讀取未經過濾的 HTML

此示例使用 formats 引數從剪貼簿讀取 HTML 資料,並以原始形式獲取程式碼,而無需瀏覽器先進行清理。

HTML

html
<textarea id="source" rows="5">
  <style>h1 {color: red;} p {color: blue;}</style>
  <h1>Hello world!</h1>
  <p>This is a test.</p>
  <script>alert('Hello world!');</script>
</textarea>
<button id="copy">Copy HTML</button>
<button id="paste_normal">Paste HTML</button>
<button id="paste_unsanitized">Paste unsanitized HTML</button>
<textarea id="destination" rows="5"></textarea>

CSS

css
body {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 5px;
}

textarea {
  grid-column: 1 / span 3;
}

JavaScript

js
const copyButton = document.getElementById("copy");
const pasteButton = document.getElementById("paste_normal");
const pasteUnsanitizedButton = document.getElementById("paste_unsanitized");
const sourceTextarea = document.getElementById("source");
const destinationTextarea = document.getElementById("destination");

copyButton.addEventListener("click", async () => {
  const text = sourceTextarea.value;
  const type = "text/html";
  const blob = new Blob([text], { type });
  const data = [new ClipboardItem({ [type]: blob })];

  try {
    await navigator.clipboard.write(data);
  } catch (error) {
    destinationTextarea.value = `Clipboard write failed: ${error}`;
  }
});

async function getHTMLFromClipboardContents(clipboardContents) {
  for (const item of clipboardContents) {
    if (item.types.includes("text/html")) {
      const blob = await item.getType("text/html");
      const blobText = await blob.text();
      return blobText;
    }
  }

  return null;
}

pasteButton.addEventListener("click", async () => {
  try {
    const clipboardContents = await navigator.clipboard.read();
    const html = await getHTMLFromClipboardContents(clipboardContents);
    destinationTextarea.value =
      html || "Could not find HTML data in the clipboard.";
  } catch (error) {
    destinationTextarea.value = `Clipboard read failed: ${error}`;
  }
});

pasteUnsanitizedButton.addEventListener("click", async () => {
  try {
    const clipboardContents = await navigator.clipboard.read({
      unsanitized: ["text/html"],
    });
    const html = await getHTMLFromClipboardContents(clipboardContents);
    destinationTextarea.value =
      html || "Could not find HTML data in the clipboard.";
  } catch (error) {
    destinationTextarea.value = `Clipboard read failed: ${error}`;
  }
});

結果

首先單擊“複製 HTML”按鈕,將第一個文字區域中的 HTML 程式碼寫入剪貼簿。然後單擊“貼上 HTML”按鈕或“貼上未經過濾的 HTML”按鈕,將經過清理或未經過濾的 HTML 程式碼貼上到第二個文字區域中。

規範

規範
Clipboard API 和事件
# dom-clipboard-read

瀏覽器相容性

另見