devicemotionevent 必须用 addeventlistener 在用户手势中注册,ios safari 需 https 且字段常为 null,需判空;acceleration 单位 m/s²(不含重力),rotationrate 单位 °/s;须节流至 30hz 并及时移除监听。

DeviceMotionEvent 事件监听必须用 addEventListener 注册
直接写 ondevicemotion = handler 在多数浏览器中无效,尤其是 iOS Safari —— 它要求用户手势触发后才能启用传感器权限。必须用 addEventListener('devicemotion', handler),且首次绑定需在用户交互(如点击、触摸)回调内执行。
常见错误现象:deviceorientation 或 devicemotion 事件完全不触发,控制台无报错,但 console.log 不输出;本质是权限未激活,而非代码语法错误。
- 必须在用户手势(
click、touchstart等)中首次调用addEventListener - iOS 13+ 要求页面为 HTTPS,HTTP 协议下该 API 直接不可用
- 部分 Android WebView(如微信内置)禁用此 API,需降级兜底
acceleration 和 rotationRate 的单位与坐标系含义
acceleration 是设备相对于惯性空间的线性加速度(单位:m/s²),不含重力;accelerationIncludingGravity 才含重力分量(常用于姿态解算)。rotationRate 是欧拉角速率(单位:°/s),对应绕 x/y/z 轴的瞬时旋转角速度。
注意:x 指向设备右侧,y 指向顶部,z 指向屏幕外 —— 这是设备固有坐标系,和页面 DOM 坐标系无关,也和地理方向无关。
-
acceleration.x:左右晃动(右为正) -
rotationRate.beta:前后俯仰(抬头为正,iOS/Safari 使用beta/gamma/alpha,非x/y/z) - Android Chrome 返回
rotationRate.alpha/beta/gamma,但值可能为null;建议优先检查rotationRate是否为null再取值
性能开销大,必须手动节流
DeviceMotionEvent 默认频率可达 60Hz,频繁读取和计算会显著拖慢主线程,尤其在低端 Android 设备上容易卡顿或丢帧。
- 不要在 handler 里直接做复杂运算或 DOM 更新
- 用
requestAnimationFrame或setTimeout+ 时间戳做 10–30ms 节流(例如每秒最多 30 次) - 避免在
devicemotion中调用console.log(尤其真机调试时,日志本身就会大幅降低采样率) - 不需要时务必调用
removeEventListener,否则内存泄漏风险高
iOS 上 accelerationIncludingGravity 可能为 null,别假设字段一定存在
iOS Safari 对传感器数据访问更保守:即使事件触发,event.acceleration、event.rotationRate 等字段仍可能为 null,特别是页面未聚焦、后台运行、或电池优化开启时。
典型错误写法:const x = event.acceleration.x → 报 Cannot read property 'x' of null。
- 每次访问前必须判空:
if (event.acceleration) { ... } - 推荐封装安全读取函数,例如:
getAccelX(event) { return event.acceleration?.x ?? 0; } - 不要依赖连续稳定的数据流,做好“偶发断连”预期(比如用户锁屏后恢复,需重新检测)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











