认识 HTML 新提案元素 <permission>:让权限请求更讲道理
它是什么
<permission> 是一个正在讨论中的 HTML 新元素。它想把“向用户申请权限”这件事,从 JavaScript 函数调用变成一个页面上真实可见的控件。目前这个提案还处于 WICG 草案阶段,经历过 Chrome 的 Origin Trial 测试,距离成为正式标准还有一段路,现在还不能在生产环境里直接使用。
它能解决什么问题
以前要申请定位、摄像头、通知这些权限,基本套路是:页面上放一个按钮,用户点一下,背后执行 navigator.permissions 或者直接调用对应的权限接口,浏览器的弹窗就跳出来了。用户常常还没看清弹窗内容,手一抖就点了拒绝。拒绝之后,权限状态变成“已阻止”,网站再想引导用户去设置里改回来,过程非常折腾。
<permission> 的设计思路是:让权限入口变成页面上的一个标签,跟在按钮、输入框一样,用户点它,就是明确想要授权。浏览器能更清楚地知道,这次权限请求确实是用户真实意图触发的。WICG 草案和 Chrome 团队的说明都提到一个关键目标:减少骚扰式弹窗,把权限动作放回到使用场景里。
基础写法
最简的用法看起来就像个普通按钮:
<permission type="camera">打开摄像头</permission>
<permission type="microphone">打开麦克风</permission>type 属性告诉浏览器要申请哪种权限,浏览器会根据这个值生成对应的授权流程。用户点击这个元素,本质上和以前点按钮触发权限接口类似,区别在于浏览器的处理方式可能更统一、更可预测。
实际项目中的稳妥写法
因为兼容性还没铺开,现在写业务代码,更好的做法是走“渐进增强”路线:支持 <permission> 的浏览器走新方案,不支持的继续用老办法兜底。下面是一个处理定位权限的示例:
<div class="permission-block">
<!-- 新方案:permission 元素 -->
<permission id="geoPermission" type="geolocation">
允许获取当前位置
</permission>
<!-- 旧方案兜底按钮,默认隐藏 -->
<button id="geoFallback" hidden>允许获取当前位置</button>
<pre id="result"></pre>
</div>const result = document.querySelector('#result');
const fallbackBtn = document.querySelector('#geoFallback');
const permissionEl = document.querySelector('#geoPermission');
function print(msg) {
result.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
}
function readLocation() {
navigator.geolocation.getCurrentPosition(
function (pos) {
const lat = pos.coords.latitude.toFixed(6);
const lng = pos.coords.longitude.toFixed(6);
print('定位成功:' + lat + ', ' + lng);
},
function (err) {
print('定位失败:' + err.code + ' ' + err.message);
},
{ enableHighAccuracy: true, timeout: 8000 }
);
}
async function init() {
try {
// 先查当前权限状态,不要一上来就申请
const status = await navigator.permissions.query({ name: 'geolocation' });
print('当前权限状态:' + status.state);
// 如果已经授权,直接定位
if (status.state === 'granted') {
readLocation();
return;
}
// 检测浏览器是否不支持 permission 元素
// 如果 permissionEl 不是真实的自定义元素实例,说明当前浏览器不认识它
if (
typeof customElements !== 'undefined' &&
!customElements.get('permission') &&
permissionEl instanceof HTMLElement
) {
// 隐藏 permission 元素,换旧按钮出场
permissionEl.hidden = true;
fallbackBtn.hidden = false;
}
// 监听权限状态变化
status.onchange = function () {
print('权限状态变更:' + status.state);
if (status.state === 'granted') {
readLocation();
}
};
} catch (e) {
// 如果连 permissions.query 都不支持,直接切旧方案
print('初始化失败:' + e.message);
permissionEl.hidden = true;
fallbackBtn.hidden = false;
}
}
// 旧方案按钮的点击处理
fallbackBtn.addEventListener('click', function () {
readLocation();
});
init();上面这段代码做了几件事:
页面加载时先用 navigator.permissions.query() 查一下权限状态,而不是直接弹出请求。
如果权限已经是“已授权”,直接执行定位逻辑。
检测浏览器是否认识 <permission> 元素,不认识就把新元素藏起来,让兜底的旧按钮显示。
监听 status.onchange,当用户在别处改了权限后,页面能及时响应。
和 Permissions API 的关系
有一点容易混淆:<permission> 不是一个用来替代 Permissions API 的东西。它们分工不同。
Permissions API 负责让代码查询权限状态、监听变化。<permission> 负责给用户一个看得见、点得到的权限入口。两者是配合关系,不是替代关系。代码里该查状态还是要查,不该一加载页面就傻等着用户授权。
怎么用才真的有用
这个标签最大的价值不在于省掉几行 JS,而在于两件事:
第一,把权限入口嵌进真实的操作流程里。比如“开始导航”旁边放定位授权按钮,“加入会议”旁边放麦克风授权按钮。用户看到的就是“我要用这个功能,所以需要这个权限”,逻辑是通的。
第二,给“被拒绝后的恢复”留了一条更自然的路。以前用户拒绝过一次,权限状态变成“已阻止”,页面再想引导就非常费劲,用户得去浏览器设置里翻半天。Chrome 对这个提案反复提到的一点就是:用户之前拒绝过,页面里也应该有更清晰的方式让用户重新同意或管理权限,不用跑到设置页。
现在要不要用
如果问我现在的态度,我不会建议大家立刻大规模上。更好的做法是挑几个权限敏感、转化容易出问题的页面做小范围试验。把 <permission> 当成一个增强能力,而不是唯一入口。新标签再新,最后也得回到一个旧问题:用户到底知不知道你为什么需要这个权限。这个问题没讲清楚,换什么标签都帮不上忙。
小结
<permission> 是一个值得关注的提案,它代表了一种趋势:浏览器厂商试图把权限请求的控制权更多还给用户,减少出其不意的弹窗。但它目前还是草案,语法细节和兼容性都可能变。如果你对这个方向感兴趣,可以关注 WICG 的官方仓库或 Chrome 平台的更新日志。真正要落到业务里,记得保持渐进增强,用老方案兜底,别把全部希望押在一个还在演进中的东西上。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!