了解剪贴板 API,更智能地与用户交互📋

2025-06-10

了解剪贴板 API,更智能地与用户交互📋

我们经常会遇到需要与用户剪贴板交互的情况。直到最近,浏览器还在使用document.execCommand剪贴板交互。这听起来很棒,而且是(现在仍然是)在 Web 应用中广泛支持的复制、剪切和粘贴方式,但问题在于剪贴板访问是异步的,只能写入DOM

背景

剪贴板访问是异步的,这意味着用户体验会因为剪贴板传输而受到影响。粘贴时情况会更糟,因为在大多数情况下,你需要清理内容才能安全处理。

当涉及到权限时,情况会变得更糟,或者浏览器必须从文本中的链接复制信息,而页面必须等待网络请求,因此使用并不那么广泛。

剪贴板 API

这一切都令人沮丧,直到新的剪贴板 API诞生。这个 API 取代了基于document.execCommand剪贴板的复制粘贴功能,它拥有定义明确的权限模型,并且不会阻塞页面。

此 API 是的属性window.navigator,由以下属性和方法构成:

  • read()
  • readText()
  • write(data)
  • writeText(text)
  • addEventListener(event, handler)
  • removeEventListener(event, handler)
  • dispatchEvent(event)

要检测浏览器是否支持该功能,您可以执行以下操作:

if (navigator.clipboard) {
  // yep, happy coding.
} else {
  // oh no 😢. Use execCommand for now
}
Enter fullscreen mode Exit fullscreen mode

除了这些优点之外,它还可以读取和写入系统剪贴板😍。剪贴板的访问需要权限 API 的支持,这意味着未经用户许可,这些操作均不被允许。

将文本复制到剪贴板

调用该方法可以将文本复制到剪贴板writeText。此函数返回一个 Promise,该 Promise 将根据操作的执行方式被解决或拒绝。

navigator.clipboard.writeText('I am writing to clipboard 📋')
  .then(() => {
    console.log('Woohoo');
  })
  .catch(err => {    
    console.error('Oh no: ', err);
  });
Enter fullscreen mode Exit fullscreen mode

调用 catch 函数的原因之一是用户未授予权限或拒绝授予权限。

您可以使用async函数和await

async function writeTextToClipboard() {
  try {
    await navigator.clipboard.writeText('I am writing to clipboard 📋');
    console.log('Woohoo');  
  } catch (err) {
    console.error('Oh no: ', err);
  }
}
Enter fullscreen mode Exit fullscreen mode

从剪贴板读取

要从剪贴板读取复制的文本,您可以使用该readText方法并等待返回的承诺:

navigator.clipboard.readText()
  .then(text => {
    console.log('Pasted content: ', text);
  })
  .catch(err => {
    console.error('Oh no: ', err);
  });
Enter fullscreen mode Exit fullscreen mode

还有async/await

async function getCopiedTextFromClioboard() {
  try {
    const text = await navigator.clipboard.readText();
    console.log('Pasted content: ', text);
  } catch (err) {
    console.error('Oh no: ', err);
  }
}
Enter fullscreen mode Exit fullscreen mode

让我们通过演示来看一下。

请注意,您必须授予其运行权限。

处理糊剂

您可以连接到 (surprise)paste事件,以便在document文本复制到剪贴板并由用户代理触发粘贴操作时接收文本。如果您想修改接收到的数据,则需要阻止事件冒泡。

document.addEventListener('paste', async (e) => {
  e.preventDefault(); // need to do something with the text
  try {
    let text = await navigator.clipboard.readText();
    text = text.toUpperCase();
    console.log('Pasted UPPERCASE text: ', text);
  } catch (err) {
    console.error('Oh no: ', err);
  }
});
Enter fullscreen mode Exit fullscreen mode

处理副本

与粘贴类似,您也可以处理复制事件:

document.addEventListener('copy', async (e) => {
  e.preventDefault(); 
  try {
    for (const item of e.clipboardData.items) {
      await navigator.clipboard.write([
        new ClipboardItem({
          [blob.type]: blob
        })
      ]);
    }
    console.log('Image copied.');
  } catch (err) {
    console.error('Oh no: ', err);
  }
});
Enter fullscreen mode Exit fullscreen mode

权限

仅支持通过HTTPSnavigator.clipboard传输的页面,并且剪贴板访问仅在允许的情况下才会受到限制,以防止进一步滥用。活动页面可以写入剪贴板,但读取剪贴板需要获得授权。

开发剪贴板 API 时引入了两个新权限:

  • clipboard-write自动授予任何活动选项卡
  • 必须clipboard-read提出请求。
const queryOpts = { name: 'clipboard-read' };
const permissionStatus = await navigator.permissions.query(queryOpts);
// Will be 'granted', 'denied' or 'prompt':
console.log(permissionStatus.state);

// Listen for changes to the permission state
permissionStatus.onchange = () => {
  console.log(permissionStatus.state);
};
Enter fullscreen mode Exit fullscreen mode

图片

我们并不经常使用文本,因此write()引入了新的方法,允许我们将其他格式的数据写入剪贴板。此方法也是异步的,实际上,writeText它是在后台调用的。

写入剪贴板

要将图像写入剪贴板,您需要将图像转换为Blob。您可以使用 Canvas 元素调用 函数来实现toBlob()。目前,您一次只能传递一张图片,Chrome 团队正在开发多张图片功能。

const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext('2d');

var img = new Image();
img.setAttribute('crossorigin', 'anonymous');
img.onload = function() {
  ctx.drawImage(img, 0, 0, 150, 150);
  img.style.display = 'none';

  canvas.toBlob(function(blob) {
    navigator.clipboard.write([
      new ClipboardItem({
        [blob.type]: blob
      })
    ]);
  })
};

img.src = 'https://image-url';
Enter fullscreen mode Exit fullscreen mode

从剪贴板读取图像

要读取图像,您需要使用该read()方法,该方法读取数据并返回对象列表ClipboardItem。您也可以使用for...of它来处理这部分内容。async

每个返回的对象可能有不同的类型,因此最佳选择是调用getType()它并进行相应的操作。在我们的例子中,对应的类型是Blob

const items = await navigator.clipboard.read(); 

for (const clipboardItem of items) {
  for (const type of clipboardItem.types) {        
    if (type === "image/png") {
      console.log(type);
      const blob = await clipboardItem.getType(type);        
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

您可以在此处看到完整的演示:

浏览器支持

截至撰写本文时,浏览器尚未支持此 API。Chrome 和 Firefox 完全支持 Clipboard API 和 ClipboardEvent API。

Edge 不支持它,但 Safari 已经支持它了。

概括

我们看到了使用这个出色的 API 操作剪贴板是多么简单和方便,以及用户体验将会有多好。

所以不用多说,祝你编码愉快💻。

鏂囩珷鏉ユ簮锛�https://dev.to/yashints/get-to-know-the-clipboard-api-be-smarter-with-user-interactions-2pp9
PREV
优化 JavaScript 切换到 HTTP/2 异步和延迟 代码拆分 明智导入 节流和防抖 那又怎样
NEXT
BDD 而非 TDD:面向结果的测试