写过前端的人都踩过这个坑——调摄像头前不知道用户有没有授权,每次都要靠 try-catch 盲猜。今天浏览器把这件事彻底透明了

调摄像头、调定位、调剪贴板,都得先猜一把用户给没给权限。try-catch 抓错误是最土的办法,catch 到的时候用户弹窗都出来了,体验早就崩了。

这个问题怎么来的

以前查权限只有两条路:要么直接调 API,失败了就 catch 住;要么记在 localStorage 里,下次直接读。但这两条都有问题——调 API 会触发授权弹窗,localStorage 里的状态跟浏览器设置随时可能不同步,用户在设置里改了权限你的缓存就废了。

Permissions API 怎么解决这个问题

navigator.permissions.query() 直接把权限状态查出来,提前知道用户给没给你:

// 查摄像头权限状态
const result = await navigator.permissions.query({ name: camera });
console.log(result.state); // granted | denied | prompt

result.addEventListener(change, () => {
  console.log(权限变了:, result.state);
});

三个状态含义很清楚:

  • granted:用户之前点过允许,不用再弹窗直接调 API 就行
  • denied:用户拒绝了,调用 API 一定会失败,别白费力气
  • prompt:还没决定,调用 API 会弹授权框

结合这个状态,你可以先给用户一个预览按钮(状态是 prompt),用户授权了再变成实时画面(状态变成 granted),全流程 UX 自己掌控,不用等浏览器弹窗救场。

支持哪些权限

除了摄像头和麦克风,这些常见权限都能查:

权限名 对应 API
camera mediaDevices.getUserMedia()
microphone mediaDevices.getUserMedia()
geolocation navigator.geolocation
notifications Notification.requestPermission()
clipboard-read navigator.clipboard.read()
clipboard-write navigator.clipboard.write()
persistent-storage navigator.storage.persist()
screen-wake-lock navigator.wakeLock.request()

完整的支持列表可以在 MDN 的 Permissions API 文档里查到,W3C 也在 2025 年更新了规范。

实战场景:地图组件

async function initMap() {
  const geo = await navigator.permissions.query({ name: geolocation });

  if (geo.state === denied) {
    showLocationDeniedUI();
    return;
  }

  if (geo.state === prompt) {
    showEnableLocationButton();
  }

  geo.addEventListener(change, ({ target }) => {
    if (target.state === granted) initMap();
  });
}

浏览器支持

Baseline Widely Available,Chrome 66+、Firefox 70+、Safari 16.4+ 全部支持,全球覆盖约 95%。这是 2022 年就定下来的成熟 API,不用担心兼容性。

怎么落地

下次写调摄像头、调定位、调剪贴板的组件,先 query 一把权限状态再决定怎么走。granted 直接调,denied 引导用户去设置,prompt 再触发真正的授权流程。UX 自己做主,不用等 catch 救场。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 15 阅读