你以为复制到剪贴板只能靠 try-catch 保底?Safari 18.2 今天把这件事用一行 API 说清楚了
你以为复制到剪贴板只能靠 try-catch 保底?Safari 18.2 今天把这件事用一行 API 说清楚了
做移动端 H5 或 PWA 的人都遇到过这个尴尬:用户点「复制 SVG 图标」,页面提示成功了,切到微信一看——粘贴出来是空的,或者变成了一张位图。iOS 和 Android 的剪贴板对格式的支持各不相同,写入失败还常常不抛错,只能靠 try-catch 蒙。
Clipboard API 规范其实规定了三种格式必须支持:text/plain、text/html、image/png。但 SVG、自定义格式这些「可能支持」的类型,写之前你根本不知道当前浏览器行不行。
Safari 18.2 给 ClipboardItem 加了 supports() 静态方法,把「能不能写」变成写之前就能回答的问题。加上 Chrome 121+ 和 Firefox 127+ 早已支持,这个 API 现在是 Baseline 2025 Newly Available(caniuse 全球覆盖率 88.62%)。
before / after
以前:写完才知道行不行
// 只能先写再接异常,失败时机不可控
async function copySVG(blob) {
try {
await navigator.clipboard.write([
new ClipboardItem({ 'image/svg+xml': blob })
]);
toast('已复制');
} catch (e) {
// 移动端这里常拿不到明确原因
toast('复制失败');
}
}
现在:写之前先问
async function copySVG(blob) {
if (ClipboardItem.supports('image/svg+xml')) {
await navigator.clipboard.write([
new ClipboardItem({ 'image/svg+xml': blob })
]);
toast('已复制 SVG');
return;
}
// 明确降级:转 PNG 再复制,用户无感知
const png = await svgToPng(blob);
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': png })
]);
toast('已复制(PNG 格式)');
}
差距不只是少一个 catch:supports() 让降级路径在用户点击前就确定——按钮文案、提示语、甚至是否展示该功能,都可以据此提前决策,而不是写完再抛错兜底。
支持现状(2026-10)
| 格式 | 支持情况 |
|---|---|
text/plain / text/html / image/png |
规范强制,supports() 恒返回 true,无需检测 |
image/svg+xml |
Chrome/Edge 124+、Opera 110+ 支持;Firefox、Safari 不支持 |
web * 自定义格式 |
仅 Chromium 系支持(Chrome/Edge 104+) |
| 浏览器 | supports() 方法 |
|---|---|
| Chrome/Edge | 121+ |
| Firefox | 127+ |
| Safari(含 iOS) | 18.4+(18.2 Release Notes 加入) |
注意区分:supports() 方法本身三引擎都已支持,但它检测的格式未必支持——比如 SVG,返回 false 是正常的,正好驱动你的降级逻辑。
移动端为什么更需要它
- 系统剪贴板权限差异:iOS 的剪贴板有「粘贴」通知条和访问频率限制,写入行为比桌面更受限
- 格式转换成本高:移动端把 SVG 转 PNG 需要 canvas 兜底,提前知道能省一次转换的耗时
- PWA 分享链路:Capacitor/Cordova 混合 App 的分享功能依赖剪贴板,格式检测能减少真机上的静默失败
下一步
- 全局搜索:项目里搜
new ClipboardItem,每个写入点前面补一行ClipboardItem.supports()检测 - 区分两类检测:三种强制格式不用测;SVG 和
web *自定义格式必测 - 设计降级:
supports()返回 false 时给明确降级(SVG→PNG、自定义格式→JSON 文本),别只弹「复制失败」
supports() 把剪贴板从「写完才知道」变成了「写前就知道」——一行检测,消灭一类移动端静默失败。
评论区
0 条评论
登录后可评论。