移动端页面上做「分享」功能,传统做法是自己弹一排图标:微信、微博、QQ,每家接一个 SDK 或拼接一个 scheme。维护成本高,覆盖还不全。其实浏览器早就给了一个更优雅的答案——navigator.share(),一行代码就能调起系统原生的分享面板,微信、备忘录、蓝牙、附近的好友,用户想发给谁就发给谁,你不用关心任何一家的接入细节。
这个 API 官方名称叫 Web Share API,2016 年就有了规范,如今在 iOS Safari 和 Android Chrome 上已经稳定可用多年。手机上刷到过那种点「分享」直接弹出系统级分享菜单的网页,基本就是它。
最小可用示例
先看代码有多简单:
const shareBtn = document.querySelector('#share');
shareBtn.addEventListener('click', async () => {
try {
await navigator.share({
title: document.title,
text: '推荐一篇好文章',
url: location.href,
});
console.log('分享成功');
} catch (err) {
console.log('分享取消或失败:', err);
}
});
点击按钮,系统分享面板弹出,用户选一个目标完成分享,整个流程结束。share() 返回一个 Promise,注意它在不同平台上的兑现时机不一样:Windows 上分享弹窗启动时就兑现,Android 上则是数据成功传给目标应用之后。所以不要依赖这个 Promise 做「分享成功」的业务统计,它更多是用来捕获异常的。
share() 接受一个对象,成员都是可选的:title(标题)、text(文本)、url(链接)、files(文件数组)。但至少得提供一个,全空或传入浏览器不认识的字段会直接抛 TypeError。title 和 text 在多数场景下会被合并成一段内容,具体呈现方式由目标应用决定。
三条硬性前提
这个 API 的限制条件比一般 Web API 多,用之前必须心里有数:
- 必须由用户手势触发。
navigator.share()不能在页面加载后或定时器里凭空调用,必须在点击、触摸这类「瞬态激活」的事件处理器里执行。这是防滥用设计——没人希望打开一个网页就被强行弹分享面板。 - 必须是 HTTPS。 Web Share API 只在安全上下文中暴露,本地开发时记得用
localhost,它被豁免。 - 受权限策略控制。 如果页面跑在 iframe 里,还需要
web-share权限策略被授予,否则调用会抛NotAllowedError。
分享文件:先问 canShare
分享文件是后来才加入的能力,支持图片、视频、音频、PDF 等常见格式。但各平台对文件类型的支持参差不齐,所以规范给了配套的检测方法 navigator.canShare():
const files = fileInput.files;
if (navigator.canShare({ files })) {
await navigator.share({
files,
title: '看看这张图',
});
} else {
console.log('当前环境不支持分享这些文件');
}
canShare() 接受和 share() 一样的参数,返回布尔值。判断文件时只传 { files } 即可。实践中的建议很简单:分享文件前必查 canShare,分享文本前查 navigator.share 是否存在就够了。
降级方案:优雅地退回剪贴板
Web Share API 至今没有进 Baseline——桌面端 Firefox 和部分桌面浏览器仍然不支持。所以特性检测加降级路径是标配写法:
async function share() {
const data = {
title: document.title,
text: '推荐一篇好文章',
url: location.href,
};
if (navigator.share) {
try {
await navigator.share(data);
return;
} catch (err) {
// 用户取消分享不是错误,静默处理即可
if (err.name !== 'AbortError') console.error(err);
return;
}
}
// 降级:复制链接
try {
await navigator.clipboard.writeText(data.url);
alert('链接已复制,去粘贴给好友吧');
} catch {
alert('请手动复制地址栏链接分享');
}
}
降级方案里最常见的坑是把用户取消也当失败处理。用户在系统面板上点了「取消」,Promise 会以 AbortError 拒绝,这属于正常流程,不该弹出错误提示,更不该重试。
几个实战经验
- 只在移动端展示分享按钮
桌面 Chrome 虽然也支持了,但桌面用户的分享习惯更依赖地址栏和 IM,原生面板带来的收益有限。可以结合pointer: coarse媒体查询或 UA 判断,只在触屏环境渲染按钮,避免无效 UI。 - url 会覆盖页面地址
传了url之后分享出去的就是这个链接而不是当前地址,做「分享指定商品而非当前筛选页」这类需求时特别有用,不用再动history.pushState。 - iOS 上 text 和 url 会拼在一起
Safari 的实现里,如果同时传了text和url,两者会被拼接成一条内容发给目标应用,换行与否由系统决定。微信收到的往往是一段「文案 + 链接」的文本,而不是带卡片的链接消息——想要卡片效果,得靠目标应用自己抓取url对应页面的 OG 标签。所以文案别写太长,留足链接的位置。 - 异常处理看 error.name
NotAllowedError多半是没绑在用户手势里,TypeError是数据有问题,AbortError是用户取消。按 name 分类处理,比笼统 catch 一个 err 靠谱得多。
写在最后
Web Share API 的价值在于「把分享还给系统」:你只负责把数据准备好,剩下的一切——展示哪些目标应用、传输、完成回调——都交给操作系统处理。代码量从一套自维护的分享矩阵缩减为一个方法调用,体验反而更贴近用户习惯。
如果你的移动端页面还在维护第三方分享 SDK,不妨先用特性检测把 navigator.share 接上,把老方案留作降级路径。
完整规范和兼容性数据请参考 MDN 的 Web Share API 官方文档。
感谢阅读,希望对你有帮助。

