写过前端的人都踩过这个坑——调摄像头前不知道用户有没有授权,每次都要靠 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 条评论
登录后可评论。