跳转到内容

能力中的 API

屏幕方向 API(锁定与解锁)

发布于 更新于

屏幕方向 API 通过 screen.orientation 暴露文档的方向。它报告当前类型和角度、触发 change 事件,并提供请求方向锁定的 lock() 与解除锁定的 unlock()(Screen Orientation,W3C)。

MDN 将 ScreenOrientation 接口标为广泛可用,但将 lock() 标为有限可用。MDN 还指出,方向锁定通常在移动设备的浏览器上下文进入全屏时启用;规范则允许用户代理把全屏或已安装的 Web 应用设为锁定前提(ScreenOrientation: lock() method,MDN;Screen Orientation,W3C)。

screen.orientation.type
screen.orientation.angle
screen.orientation.addEventListener("change", listener)
await screen.orientation.lock(orientation)
screen.orientation.unlock()

应用锁定后,lock() 返回的 Promise 以 undefined 兑现。unlock() 返回 undefined;规范解释,用户代理可能无法预知回到默认方向是否会改变屏幕(Screen Orientation,W3C)。

screen.orientation 是 ScreenOrientation 对象,包含规范定义的以下成员。

成员 类型 说明
type OrientationType(只读) 当前值:portrait-primary、portrait-secondary、landscape-primary 或 landscape-secondary。
angle unsigned short(只读) 屏幕相对其自然方向逆时针旋转的角度。
lock(orientation) Promise<undefined> 请求锁定到一个 OrientationLockType 值。
unlock() undefined 解除活动锁定并回到默认方向。
onchange EventHandler 处理报告的方向类型或角度改变时触发的 change 事件。

orientation 参数接受 any、natural、landscape、portrait、portrait-primary、portrait-secondary、landscape-primary 或 landscape-secondary。规范允许用户代理或平台只支持其中一部分锁定值(OrientationLockType enum,W3C)。

规范为 lock() 定义了以下失败情况。

它的通用安全检查也会同步应用于 unlock()。

异常 条件
InvalidStateError 文档不是受到用户关注的顶级可遍历对象的 fully active 后代。
SecurityError 文档已隐藏,或设置了 sandboxed orientation lock 标志。
NotSupportedError 用户代理无法锁定到请求的值,或平台、用户偏好或其他限制阻止了尝试。
NotAllowedError 用户代理要求锁定前提,例如全屏或已安装的 Web 应用,而文档不满足条件。
AbortError 另一个 lock() 请求会取消待处理的锁定请求。屏幕存在活动方向锁定时,unlock() 也会取消该请求。

unlock() 会先检查屏幕的活动方向锁定。该值为 null 时,方法会在检查待处理的锁定 Promise 前返回 undefined。否则,待处理的锁定 Promise 会以 AbortError 拒绝,随后用户代理应用默认方向锁定(Screen Orientation,W3C)。

下面的示例会先检测要使用的屏幕方向成员。各自的回退分支保留响应式行为,不尝试不可用的操作。

把这段脚本粘贴到页面中。它会创建按钮和状态输出,锁定前请求全屏,并在下一次点击时解除两种状态。

const button = document.createElement("button");
const status = document.createElement("output");
button.textContent = "锁定横向";
document.body.append(button, status);
let locked = false;
button.addEventListener("click", async () => {
const orientation = screen.orientation;
if (typeof orientation?.lock !== 'function') {
const axis = matchMedia("(orientation: portrait)").matches
? "纵向"
: "横向";
status.value = `锁定不可用;响应式布局当前为${axis}。`;
return;
}
try {
if (!locked) {
if (!document.fullscreenElement) {
await document.documentElement.requestFullscreen();
}
await orientation.lock("landscape");
locked = true;
button.textContent = "解除方向锁定";
status.value = `已锁定:${orientation.type},${orientation.angle} 度。`;
} else {
orientation.unlock();
if (document.fullscreenElement) await document.exitFullscreen();
locked = false;
button.textContent = "锁定横向";
status.value = "方向已解锁。";
}
} catch (error) {
status.value = `${error.name}:未锁定方向。`;
}
});

catch 分支处理被拒绝的全屏和方向请求。功能检测分支把布局控制权留给 CSS,因此 lock() 缺失时页面仍可使用。

在 change 处理函数中重新读取 type 与 angle,因为该事件表示这些报告值已经改变。

function renderOrientation() {
const current = screen.orientation;
document.documentElement.dataset.orientation = current.type;
console.log(`${current.type}:${current.angle} 度`);
}
if (screen.orientation) {
screen.orientation.addEventListener("change", renderOrientation);
renderOrientation();
} else {
const portrait = matchMedia("(orientation: portrait)");
const renderFallback = () => {
document.documentElement.dataset.orientation = portrait.matches
? "portrait"
: "landscape";
};
portrait.addEventListener("change", renderFallback);
renderFallback();
}

回退保留纵向或横向的区别,但不会虚构媒体查询没有提供的 primary 或 secondary 方向值。

规范

规范状态
Screen Orientation: ScreenOrientation interfaceW3C 草案
Screen Orientation: lock() methodW3C 草案
Screen Orientation: unlock() methodW3C 草案