- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
导读
usePointerLock是 VueUse 核心包中面向Pointer Lock API的响应式封装组合式函数(Composable)。在 3D 游戏、第一人称视角漫游、拖拽画布等场景中,我们需要把鼠标指针"隐藏"并持续捕获其位移增量,而 Pointer Lock API 正是浏览器提供的标准能力。读完本文,你将掌握usePointerLock的完整 API、Composable 与组件两种用法、底层实现原理(事件监听、锁定时序、错误处理),以及它在 VueUse 官方 demo(3D 立方体旋转)中的真实落地方式。
一、快速上手:Composable 用法
usePointerLock通过 VueUse 的入口统一导出(见 packages/core/index.ts),使用方式非常简洁:
import { usePointerLock } from '@vueuse/core' const { isSupported, lock, unlock, element, triggerElement, } = usePointerLock()返回值一览
| 返回值 | 类型 | 说明 |
|---|---|---|
isSupported | ComputedRef<boolean> | 当前浏览器环境是否支持 Pointer Lock API |
lock | (e: MaybeElementRef \| Event) => Promise<MaybeElement> | 发起指针锁定,返回 Promise,锁定成功后 resolve 为被锁定的元素 |
unlock | () => Promise<boolean> | 解除指针锁定,成功返回true |
element | ShallowRef<MaybeElement> | 当前被锁定的 DOM 元素(未锁定时为null) |
triggerElement | ShallowRef<MaybeElement> | 触发锁定的元素(如按钮、画布) |
其中MaybeElement的类型定义位于 unrefElement/index.ts,指HTMLElement | SVGElement | VueInstance | undefined | null;MaybeElementRef即MaybeRef<T>,既可以是元素本身,也可以是元素对应的 ref。
二、Component 组件用法
如果更倾向于模板语法,VueUse 还提供了对应的UsePointerLock渲染组件(实现见 usePointerLock/component.ts),通过作用域插槽(scoped slot)暴露同样的响应式数据:
<template> <UsePointerLock v-slot="{ lock }"> <canvas /> <button @click="lock"> Lock Pointer on Canvas </button> </UsePointerLock> </template>组件支持两个 props:
as:默认渲染为div,可通过该 prop 指定要渲染的标签名(如canvas);document:自定义 document 实例,用于 iframe 或测试环境。
组件内部会把usePointerLock(target)的返回值用reactive()包裹后注入默认插槽,同时给根元素绑定targetref,这样lock事件(如@click="lock")会以 Event 形式传入,自动将根元素识别为锁定目标。
三、锁定与解锁:lock/unlock的完整时序
1.lock:发起并等待锁定成功
async function lock(e: MaybeElementRef | Event) { if (!isSupported.value) throw new Error('Pointer Lock API is not supported by your browser.') triggerElement.value = e instanceof Event ? <HTMLElement>e.currentTarget : null targetElement = e instanceof Event ? unrefElement(target) ?? triggerElement.value : unrefElement(e) if (!targetElement) throw new Error('Target element undefined.') targetElement.requestPointerLock() return await until(element).toBe(targetElement) }从源码(usePointerLock/index.ts)可以看出lock同时支持两类入参:
- 传入事件对象(
Event):例如在模板中@click="lock",此时currentTarget会被记入triggerElement,锁定目标优先取 composable 初始化时传入的target,否则回退到triggerElement; - 传入元素或元素 ref(
MaybeElementRef):直接以unrefElement(e)作为锁定目标。
确认目标元素后调用原生requestPointerLock(),随后借助until(element).toBe(targetElement)(来自 @vueuse/shared 的 until)等待pointerlockchange事件把element更新为目标元素——也就是说,lock返回的 Promise 会在锁定真正生效后才 resolve,而不是调用后立即返回。
2.unlock:解除锁定
async function unlock() { if (!element.value) return false document!.exitPointerLock() await until(element).toBeNull() return true }当没有元素处于锁定状态时直接返回false;否则调用原生document.exitPointerLock(),并等待element变回null(即锁定解除生效)后返回true。
四、底层原理:事件监听与状态同步
usePointerLock的响应式状态完全由两个原生事件驱动,事件监听逻辑见 usePointerLock/index.ts,均使用{ passive: true }监听选项:
pointerlockchange:指针锁定状态发生变化时触发。源码用document.pointerLockElement ?? element.value取当前锁定元素;只有当targetElement存在且与当前锁定元素一致时,才把document.pointerLockElement同步到element.value;若锁定已解除,则将targetElement与triggerElement一并清空为null。pointerlockerror:获取或释放锁失败时触发。此时根据document.pointerLockElement是否还存在判断是「获取失败(acquire)」还是「释放失败(release)」,并抛出对应的错误信息。
值得注意的边界情况:当调用lock时传入了target(即usePointerLock(target)初始化参数),后续任何元素的pointerlockchange事件都不会影响本 composable 的状态,只有target相关的锁变化才会被同步——这也是源码中if (targetElement && currentElement === targetElement)判断的用意。
五、能力检测:isSupported与useSupported
isSupported通过 VueUse 的通用能力检测函数useSupported(实现见 useSupported/index.ts)计算得出:
const isSupported = useSupported(() => document && 'pointerLockElement' in document)useSupported内部先调用useMounted确保在组件挂载后才计算;- 检测逻辑为「存在 document 且其上有
pointerLockElement属性」,这等价于判断浏览器是否实现 Pointer Lock API。
因此usePointerLock是完全 SSR 安全的:服务端渲染时defaultDocument为undefined(见 core/_configurable.ts),isSupported为false,事件监听与锁定逻辑都不会执行。
六、官方 Demo 实战:3D 立方体旋转
VueUse 为usePointerLock提供了可视化 demo(usePointerLock/demo.vue),演示了指针锁定在 3D 场景中最典型的使用方式——第一人称/轨道旋转控制:
<script setup lang="ts"> import { useMouse, usePointerLock } from '@vueuse/core' import { shallowRef, watch } from 'vue' const { lock, unlock, element } = usePointerLock() const { x, y } = useMouse({ type: 'movement' }) const rotY = shallowRef(-45) const rotX = shallowRef(0) watch([x, y], ([x, y]) => { if (!element.value) return rotY.value += x / 2 rotX.value -= y / 2 }) </script>关键思路:
usePointerLock()返回lock/unlock/element;useMouse({ type: 'movement' })只跟踪鼠标位移增量(movementX/movementY),指针锁定后该数据即代表旋转角度的变化;- 模板中在立方体容器上绑定
@mousedown.capture="lock"与@mouseup="unlock"——按下时锁定指针,松开时解除锁定,形成"按住拖动旋转"的交互; watch([x, y])内先检查element.value是否存在,只有确实处于锁定状态时才累加旋转角rotY/rotX,避免未锁定时的误旋转。
对应的浏览器测试 usePointerLock/demo.browser.test.ts 验证了 demo 的渲染以及 hover / click 不会抛出错误,可作为接入测试的参考。
七、配置选项与适用场景总结
Options
usePointerLock的选项继承ConfigurableDocument(见 core/_configurable.ts):
export interface UsePointerLockOptions extends ConfigurableDocument { // pointerLockOptions?: PointerLockOptions }document?: Document:自定义 document 实例,典型用于iframe 环境(锁定发生在 iframe 内)或测试环境(注入 jsdom 等 mock document)。默认取window.document(客户端)。
典型适用场景
- 3D 场景 / 游戏中的鼠标视角控制(如官方 demo 的立方体旋转);
- 全屏绘图、白板类应用中需要隐藏光标并持续跟踪位移的场景;
- 任何需要「捕获鼠标指针并消除系统光标」的沉浸式交互。
使用注意事项
- 浏览器兼容性:先检查
isSupported.value,为不支持的浏览器提供降级方案; - 锁定元素必须可见:Pointer Lock API 要求目标元素在文档中可见,且锁定请求通常需要发生在用户手势(如 click / mousedown)处理函数内,因此 demo 中使用
@mousedown.capture很关键; - Esc 键自动退出:用户按
Esc或系统会自动解除指针锁定,此时pointerlockchange会触发,element会被清空,业务侧应监听该变化(如暂停游戏循环); - 异步时序:
lock/unlock返回的 Promise 会等待状态真正切换完成,可利用await保证后续逻辑的时序正确性。
八、小结
usePointerLock以约 100 行源码(usePointerLock/index.ts)完整封装了 Pointer Lock API 的能力检测、事件监听、锁定/解锁时序与响应式状态同步,并提供 Composable 与UsePointerLock组件两种使用形式。无论是游戏视角控制还是沉浸式绘图,它都能让你用最少的代码获得类型安全、SSR 安全且可测试的指针锁定能力——这也是 VueUse "Essential Vue Composition Utilities" 设计理念的一个典型缩影。
- 前端
【免费下载链接】vueuse
Collection of essential Vue Composition Utilities for Vue 3
相关推荐
在 Vue 3 / Nuxt 项目中响应式封装 Pointer Lock API:Airi 仓库 vueuse-functions 技能中的 usePointerLock 完全指南
在 Vue 3 / Nuxt 项目中响应式封装 Pointer Lock API:Airi 仓库 vueuse functions 技能中的 usePointe
AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染three.js PointerLockControls 完全指南:基于 Pointer Lock API 的第一人称视角控制
three.js PointerLockControls 完全指南:基于 Pointer Lock API 的第一人称视角控制 本文围绕 three.js 中的
前端3D渲染图形学VueUse 中 useGeolocation 全面指南:基于 Geolocation API 的响应式地理定位
VueUse 中 useGeolocation 全面指南:基于 Geolocation API 的响应式地理定位 本文是一份面向 Vue 3 开发者的实战指南,
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考