浏览器 API 之光标锁
本文部分内容参考 MDN。
Pointer Lock API(以前叫做 Mouse Lock API)提供了一种基于鼠标移动的输入方式(例如移动量),而不仅仅是鼠标指针在屏幕上的绝对位置。通过这个 API,光标可以被隐藏掉,并且鼠标事件不再受屏幕边缘的限制,你可以连续不断的向同一方向拖动鼠标而鼠标事件不会中断。
如此,这个 API 可以用在许多依靠鼠标移动事件的网页上,最佳的实践莫过于 FPS 游戏了:FPS 游戏需要通过鼠标控制视角的方向,而传统的鼠标事件会在光标移出浏览器边界的时候停止,所以在该 API 出现前在浏览器中运行一个 FPS 游戏是很不现实的。有了这个 API,玩家可以随意的移动鼠标而不用担心鼠标移出浏览器然后点击中另外一个程序而使浏览器失去焦点。
基础概念
光标锁和 Mouse Capture 类似。Mouse Capture 在鼠标被拖动时也能提供连续的鼠标事件,但是在鼠标按钮释放时会停止。光标锁 API 和 Mouse Capture 有以下的区别:
- 它是持续的:直至特定的 API 被调用或用户使用特定的方式退出前,光标不会被释放。
- 它不受浏览器或屏幕边缘的限制。
- 无论鼠标是否被按下,它都可以连续的发送事件。
- 鼠标指针会被隐藏。
方法和属性概览
这一节提供了光标锁 API 标准中的方法和属性。
requestPointerLock()
requestPointerLock()是光标锁的主要函数,类似全屏 API,它位于 DOM 元素中。鉴于现在该 API 有不少浏览器还需要前缀,所以你可以像下面这样声明和调用:
pointerLockElement 及 exitPointerLock()
光标锁 API 也在 Document 对象中加入了 pointerLockElement 属性和 exitPointerLock()方法。
pointerLockElement 属性一般用来确定元素是否已经锁定光标:
exitPointerLock()方法,顾名思义是用来退出光标锁定状态的:
pointerlockchange 事件
当光标锁的状态改变的时候会发生这个事件。比如当 requestPointerLock()、exitPointerLock()被调用时或者用户按下 ESC 键时,光标锁状态都会改变。pointerlockchange 事件会被分发给 document
,下面是一个例子:
pointerlockerror 事件
当调用 requestPointerLock()或 exitPointerLock()时,如果有错误发生那么这个事件就会被分发给 document
:
提示
在 Firefox 50 以前,上面的事件都有前缀 moz。
鼠标事件的扩展
光标锁 API 向普通的 MouseEvent 事件中添加了 movementX 和 movementY 两个属性,这两个属性提供了鼠标位置的改变量。
提示
这是改变量,与指针在屏幕上的位置是有区别的,可以理解为这一次事件和上一次事件的 screenX(Y)的差值。
锁定时
当光标被锁定时,标准 MouseEvent 中的 clientX、clientY、screenX 和 screenY 都会保持不变。movementX 和 movementY 的值没有极限,只要鼠标(这里指硬件)可以随意移动。此时,鼠标指针会被锁定且隐藏,所以不会有屏幕边缘的限制。
未锁定时
为了方便,在光标未锁定时,movementX 和 movementY 的值同样也是有效的。
光标未锁定时,光标可能离开 / 进入浏览器,此时 movementX 和 movementY 都会被置 0。
简单的示例
这是一个 GitHub 上的示例(源代码)
iframe 中的限制
光标锁只能同时锁定一个 iframe。如果你锁定了一个 iframe,那么你将不能再锁定另一个 iframe,如果你这么做了,那么会抛出一个错误。为了避免这一限制,你应该先解除锁定,然后在为新的 iframe 进行锁定。
“sandbox” iframe 默认会拒绝锁定光标,除非你这么设置,Chrome 在不久的将来支持:
规范
规范 | 状态 | 备注 |
---|---|---|
Pointer Lock | 候选 | 原始定义 |
兼容性
桌面系统 | 特性 | Chrome | Edge | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit) |
---|---|---|---|---|---|---|---|
基础支持 | (Yes) | (Yes) | (Yes)-moz | 不支持 | (Yes) | 10.1 | |
无前缀支持 | (Yes) | (Yes) | 50 (50) | 不支持 | (Yes) | 10.1 | |
手机系统 | 目前看来全都不支持 |
兼容性表来自 MDN,版本为 Feb 14, 2017, 3:29:30 AM。