更新记录

1.1.0(2026-06-25) 下载此版本

  • 重构插件目录结构,拆分 core、services、entities、utils、game 模块。
  • 新增权限服务、实时监听服务、单次获取服务、生命周期服务、能力检测服务。
  • 修复浏览器切换后台再返回后监听状态和数据缓存异常的问题。
  • 新增统一陀螺仪数据实体,补充 timestamp、source、alpha、beta、gamma、radianX、radianY、radianZ、isValid、isStale、raw 字段。
  • 新增 getGyroscope 单次获取 API。
  • 新增 requestGyroscopePermission 独立权限申请 API。
  • 修复 startGyroscope({ interval }) 未真实限制业务回调频率的问题。
  • 新增游戏重力控制器、虚拟摇杆、倾斜方向识别和归一化工具 API。

1.0.0(2025-07-08) 下载此版本

H5 陀螺仪插件 - 为 uni-app 提供 H5 平台的陀螺仪功能支持


平台兼容性

uni-app(4.44)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

jz-h5-gyroscope

H5 陀螺仪插件 - 为 uni-app 提供 H5 平台陀螺仪能力。

当前版本已从单文件实现升级为模块化实现,除了兼容原来的实时监听 API,还新增了权限申请、单次获取、状态检测、后台恢复、游戏重力控制、虚拟摇杆、倾斜方向识别等能力。

功能概览

兼容原有能力

  • startGyroscope(options):开始实时监听陀螺仪。
  • stopGyroscope(options):停止实时监听。
  • onGyroscopeChange(callback):监听陀螺仪变化。
  • offGyroscopeChange(callback):取消监听陀螺仪变化。
  • getGyroscopeStatus():获取当前监听状态。

新增能力

  • getGyroscope(options):单次获取一次陀螺仪数据。
  • requestGyroscopePermission(options):单独申请 iOS 陀螺仪权限。
  • getGyroscopeSupportInfo():获取当前浏览器传感器支持情况。
  • normalizeGyroscope(data, options):把角度数据转换成 -1 ~ 1 的游戏输入值。
  • toGravityVector(data, options):把陀螺仪数据转换成重力移动向量。
  • createGameController(options):创建游戏重力控制器,适合重力球、体感移动等场景。
  • createVirtualJoystick(options):创建陀螺仪虚拟摇杆。
  • getTiltDirection(data, options):获取当前倾斜方向。

适用场景

  • H5 页面获取手机陀螺仪数据。
  • iOS Safari / Android 浏览器中实现体感控制。
  • 重力球、倾斜移动、飞行控制、方向识别。
  • 把手机倾斜转换成游戏摇杆输入。
  • 需要兼容 uni-app 风格 API 的 H5 项目。

平台支持

平台 支持情况 说明
H5 Safari iOS 支持 iOS 13+ 需要用户点击触发权限申请
H5 Chrome Android 支持 通常无需额外权限
H5 微信浏览器 Android 支持 依赖设备和浏览器传感器能力
H5 微信浏览器 iOS 可能支持 受 iOS WebView 和权限策略影响
H5 PC 浏览器 部分支持 大多数 PC 没有陀螺仪传感器
App 不支持 请使用 uni-app 官方 API
小程序 不支持 请使用小程序官方 API

安装和导入

import jzH5Gyroscope from '@/uni_modules/jz-h5-gyroscope/index.js'

快速开始

基础实时监听

export default {
  data() {
    return {
      gyroscopeData: null
    }
  },

  onLoad() {
    jzH5Gyroscope.onGyroscopeChange(data => {
      this.gyroscopeData = data
      console.log('陀螺仪数据', data)
    })
  },

  methods: {
    startGyroscope() {
      jzH5Gyroscope.startGyroscope({
        interval: 200,
        success: res => {
          console.log('启动成功', res)
        },
        fail: err => {
          console.log('启动失败', err)
        },
        complete: res => {
          console.log('调用结束', res)
        }
      })
    },

    stopGyroscope() {
      jzH5Gyroscope.stopGyroscope({
        success: res => {
          console.log('停止成功', res)
        }
      })
    }
  },

  onUnload() {
    jzH5Gyroscope.stopGyroscope()
    jzH5Gyroscope.offGyroscopeChange()
  }
}

iOS 端请把 startGyroscope 绑定到按钮点击事件,不要在 onLoadmounted 中自动启动。

iOS 使用方式

iOS 13+ 的 Safari 要求陀螺仪权限必须由用户手势触发,例如按钮点击。

推荐写法:

methods: {
  startByUserTap() {
    jzH5Gyroscope.requestGyroscopePermission({
      success: () => {
        jzH5Gyroscope.onGyroscopeChange(data => {
          console.log('陀螺仪数据', data)
        })

        jzH5Gyroscope.startGyroscope({
          interval: 200,
          success: res => {
            console.log('监听已启动', res)
          },
          fail: err => {
            console.log('启动失败', err)
          }
        })
      },
      fail: err => {
        console.log('权限申请失败', err)
      }
    })
  }
}

模板示例:

<button @click="startByUserTap">开启陀螺仪</button>

iOS 注意事项

  • 必须使用 HTTPS 页面。
  • 权限申请必须由点击、触摸等用户动作触发。
  • 如果 Safari 设置中关闭了“动作与方向访问”,浏览器可能不会返回数据。
  • iOS 微信浏览器、部分 App 内置 WebView 可能受到系统限制,不能保证所有版本都可用。

API 文档

startGyroscope(options)

开始实时监听陀螺仪数据。

jzH5Gyroscope.startGyroscope({
  interval: 200,
  success(res) {},
  fail(err) {},
  complete(res) {}
})

参数:

参数 类型 默认值 说明
interval Number/String 200 回调触发间隔,单位 ms
success Function - 启动成功回调
fail Function - 启动失败回调
complete Function - 调用完成回调

interval 支持:

实际间隔
20 20ms
60 60ms
200 200ms
'game' 20ms
'ui' 60ms
'normal' 200ms

说明:

  • 插件会先更新内部最新数据,再根据 interval 节流业务回调。
  • 页面切后台后不会清空最近数据。
  • 页面恢复后,如果用户没有主动停止,会自动重新绑定传感器监听。

stopGyroscope(options)

停止实时监听。

jzH5Gyroscope.stopGyroscope({
  success(res) {},
  fail(err) {},
  complete(res) {}
})

说明:

  • 这是用户主动停止。
  • 停止后页面恢复不会自动重新监听。
  • 最近一次有效数据会保留,可用于状态查看或短时间缓存读取。

onGyroscopeChange(callback)

注册实时数据回调。

const callback = data => {
  console.log(data.x, data.y, data.z)
}

jzH5Gyroscope.onGyroscopeChange(callback)

说明:

  • 相同 callback 不会重复注册。
  • 回调频率受 startGyroscope({ interval }) 控制。

offGyroscopeChange(callback)

取消监听。

// 取消指定回调
jzH5Gyroscope.offGyroscopeChange(callback)

// 取消全部回调
jzH5Gyroscope.offGyroscopeChange()

getGyroscope(options)

单次获取一次陀螺仪数据。

适合只需要获取一次当前手机姿态的场景。

jzH5Gyroscope.getGyroscope({
  maxAge: 300,
  timeout: 1000,
  success(data) {
    console.log('单次数据', data)
  },
  fail(err) {
    console.log('获取失败', err)
  },
  complete(res) {}
})

参数:

参数 类型 默认值 说明
maxAge Number 300 可接受缓存数据的最大时长,单位 ms
timeout Number 1000 没有缓存时等待新数据的超时时间,单位 ms
success Function - 获取成功回调
fail Function - 获取失败回调
complete Function - 完成回调

规则:

  • 有未过期缓存时,立即返回缓存数据。
  • 没有缓存时,临时监听下一次真实传感器事件。
  • 如果原本没有启动实时监听,单次获取完成后会自动停止临时监听。
  • 超时仍无数据时返回失败。

requestGyroscopePermission(options)

单独申请陀螺仪权限。

jzH5Gyroscope.requestGyroscopePermission({
  success(res) {
    console.log('权限结果', res)
  },
  fail(err) {
    console.log('权限失败', err)
  },
  complete(res) {}
})

返回示例:

{
  granted: true,
  state: 'granted',
  required: true,
  errMsg: 'requestGyroscopePermission:ok'
}

字段说明:

字段 说明
granted 是否已授权
state 权限状态,常见值为 granteddeniedprompt
required 当前浏览器是否需要主动权限申请
errMsg 调用结果信息

getGyroscopeStatus()

获取当前插件状态。

const status = jzH5Gyroscope.getGyroscopeStatus()
console.log(status)

返回示例:

{
  isListening: true,
  isPageHidden: false,
  isSupported: true,
  interval: 200,
  callbackCount: 1,
  lastData: null,
  lastEventAt: 0,
  errMsg: 'getGyroscopeStatus:ok'
}

字段说明:

字段 说明
isListening 是否处于监听状态
isPageHidden 页面是否处于后台或隐藏状态
isSupported 当前浏览器是否支持传感器事件
interval 当前业务回调间隔
callbackCount 当前注册的回调数量
lastData 最近一次有效陀螺仪数据
lastEventAt 最近一次传感器事件时间戳
errMsg 状态信息

getGyroscopeSupportInfo()

获取浏览器传感器支持信息。

const support = jzH5Gyroscope.getGyroscopeSupportInfo()
console.log(support)

返回示例:

{
  hasDeviceOrientation: true,
  hasDeviceMotion: true,
  isSecureContext: true,
  needsPermission: true,
  isSupported: true
}

字段说明:

字段 说明
hasDeviceOrientation 是否支持 DeviceOrientationEvent
hasDeviceMotion 是否支持 DeviceMotionEvent
isSecureContext 当前页面是否为安全上下文
needsPermission 是否需要主动调用权限申请
isSupported 是否至少支持一种传感器事件

数据结构

实时监听、单次获取返回的 data 结构:

{
  x: 0,
  y: 0,
  z: 0,
  alpha: 0,
  beta: 0,
  gamma: 0,
  radianX: 0,
  radianY: 0,
  radianZ: 0,
  timestamp: 0,
  source: 'deviceorientation',
  isValid: true,
  isStale: false,
  raw: null
}

字段说明:

字段 说明
x 兼容字段,对应 beta
y 兼容字段,对应 gamma
z 兼容字段,对应 alpha
alpha 浏览器原始 Z 轴方向角
beta 浏览器原始 X 轴方向角
gamma 浏览器原始 Y 轴方向角
radianX x 对应弧度值
radianY y 对应弧度值
radianZ z 对应弧度值
timestamp 数据产生时间戳
source 数据来源,deviceorientationdevicemotion
isValid 数据是否有效
isStale 是否为过期缓存数据
raw 浏览器原始事件对象

游戏能力

normalizeGyroscope(data, options)

把陀螺仪角度转换成 -1 ~ 1 的归一化输入。

适合自己实现游戏控制逻辑。

const normalized = jzH5Gyroscope.normalizeGyroscope(data, {
  maxAngle: 45,
  sensitivity: 1,
  deadZone: 0.05,
  adjustScreen: true
})

console.log(normalized.x, normalized.y)

返回示例:

{
  x: 0.25,
  y: -0.4,
  source: 'deviceorientation',
  raw: data
}

参数:

参数 默认值 说明
maxAngle 45 最大倾斜角,超过后按最大值计算
sensitivity 1 灵敏度
deadZone 0 死区,小于该值按 0 处理
adjustScreen true 是否根据横竖屏修正方向

toGravityVector(data, options)

把陀螺仪数据转换成游戏移动向量。

const vector = jzH5Gyroscope.toGravityVector(data, {
  sensitivity: 1.2,
  deadZone: 0.05,
  maxStrength: 1,
  smoothFactor: 0.2,
  invertX: false,
  invertY: false,
  maxAngle: 45,
  adjustScreen: true
})

console.log(vector)

返回示例:

{
  x: 0.25,
  y: -0.4,
  length: 0.47,
  angle: -57.99,
  direction: 'right-up',
  strength: 0.47
}

createGameController(options)

创建一个可持续使用的重力控制器。

相比 toGravityVector,它会保留上一次数据,用于平滑滤波,适合游戏循环中持续调用。

const controller = jzH5Gyroscope.createGameController({
  sensitivity: 1.2,
  deadZone: 0.05,
  smoothFactor: 0.2
})

jzH5Gyroscope.onGyroscopeChange(data => {
  const vector = controller.update(data)
  player.x += vector.x * 5
  player.y += vector.y * 5
})

控制器方法:

方法 说明
update(data, options) 输入陀螺仪数据,返回游戏向量
reset() 清空平滑滤波历史

配置参数:

参数 默认值 说明
sensitivity 1 灵敏度
deadZone 0.05 死区
maxStrength 1 最大强度
smoothFactor 0.2 平滑系数,越小越平滑
invertX false 是否反转 X 方向
invertY false 是否反转 Y 方向
maxAngle 45 最大倾斜角
adjustScreen true 是否根据横竖屏修正方向

createVirtualJoystick(options)

把陀螺仪转换成类似虚拟摇杆的数据。

const joystick = jzH5Gyroscope.createVirtualJoystick({
  deadZone: 0.08,
  sensitivity: 1
})

jzH5Gyroscope.onGyroscopeChange(data => {
  const joy = joystick.update(data)

  if (joy.pressed) {
    console.log('摇杆方向', joy.direction)
    console.log('轴值', joy.axisX, joy.axisY)
  }
})

返回示例:

{
  axisX: 0.25,
  axisY: -0.4,
  pressed: true,
  strength: 0.47,
  direction: 'right-up'
}

getTiltDirection(data, options)

获取倾斜方向。

const direction = jzH5Gyroscope.getTiltDirection(data, {
  deadZone: 0.05,
  mode: 'eight'
})

console.log(direction)

方向值:

center
left
right
up
down
left-up
left-down
right-up
right-down

参数:

参数 默认值 说明
deadZone 0.05 死区
mode eight four 四方向,eight 八方向

完整游戏示例

import jzH5Gyroscope from '@/uni_modules/jz-h5-gyroscope/index.js'

export default {
  data() {
    return {
      player: {
        x: 100,
        y: 100
      },
      controller: null
    }
  },

  onLoad() {
    this.controller = jzH5Gyroscope.createGameController({
      sensitivity: 1.5,
      deadZone: 0.05,
      smoothFactor: 0.15
    })

    jzH5Gyroscope.onGyroscopeChange(this.handleGyroscope)
  },

  methods: {
    startGameControl() {
      jzH5Gyroscope.startGyroscope({
        interval: 'game',
        success: () => {
          console.log('体感控制已开启')
        }
      })
    },

    handleGyroscope(data) {
      const vector = this.controller.update(data)
      this.player.x += vector.x * 5
      this.player.y += vector.y * 5
    }
  },

  onUnload() {
    jzH5Gyroscope.offGyroscopeChange(this.handleGyroscope)
    jzH5Gyroscope.stopGyroscope()
  }
}

错误对象

失败时通常返回:

{
  errMsg: 'startGyroscope:fail 当前浏览器不支持陀螺仪功能',
  code: 'NOT_SUPPORTED',
  method: 'startGyroscope',
  detail: null
}

常见错误码:

错误码 说明
NOT_SUPPORTED 当前浏览器不支持传感器事件
PERMISSION_DENIED 用户拒绝权限
PERMISSION_ERROR 权限申请异常
TIMEOUT 单次获取超时
NO_VALID_DATA 没有获取到有效数据

兼容性和注意事项

HTTPS 要求

现代浏览器通常要求 HTTPS 页面才能访问传感器。

iOS 权限要求

iOS 13+ 必须在用户点击中调用权限申请或启动监听:

<button @click="startGyroscope">开启</button>

不要这样做:

onLoad() {
  jzH5Gyroscope.startGyroscope()
}

后台恢复

插件会监听页面生命周期:

  • 页面隐藏时移除传感器监听,但保留最近数据。
  • 页面恢复时,如果不是用户主动停止,会重新绑定监听。
  • getGyroscopeStatus().lastData.isStale 可判断最近数据是否过期。

数据方向

基础数据中:

  • x = beta
  • y = gamma
  • z = alpha

游戏 API 会默认根据横竖屏修正方向。如果不需要修正,可以传入:

{
  adjustScreen: false
}

与旧版本差异

能力 旧版本 新版本
目录结构 单文件 多模块拆分
权限申请 启动时内部处理 支持单独调用 requestGyroscopePermission
实时监听 支持 支持,且 interval 真实生效
回调管理 数组,可能重复 Set 去重
单次获取 不支持 支持 getGyroscope
状态查询 简单状态 增加页面隐藏、支持情况、最近事件时间
后台恢复 不完善 页面恢复后自动续接监听
数据结构 { x, y, z } 扩展 timestamp/source/raw/isStale 等字段
游戏能力 不支持 支持重力向量、虚拟摇杆、方向识别

更新日志

v1.1.0

  • 模块化重构插件代码。
  • 新增权限服务、实时监听服务、单次获取服务、生命周期服务、能力检测服务。
  • 新增 getGyroscope 单次获取。
  • 新增 requestGyroscopePermission 独立权限申请。
  • 新增 getGyroscopeSupportInfo 能力检测。
  • 修复 interval 未真实限制业务回调频率的问题。
  • 修复页面后台切换后数据异常和监听恢复问题。
  • 新增游戏重力控制器、虚拟摇杆、倾斜方向识别。

v1.0.0

  • 初始版本发布。
  • 支持 H5 陀螺仪实时监听。
  • 支持 iOS 权限请求。

许可证

MIT License


本插件仅面向 H5 环境。App、小程序等平台请优先使用对应平台官方陀螺仪 API。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

陀螺仪权限

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议