HTML Vibration API震动反馈详解
先说两个核心判断:想让手机震动一下,远没有想象中那么“一调用就嗡嗡嗡”,尤其是碰上iOS的设备,各种限制和坑简直能写一部长篇连续剧。不过摸清门道之后,也就那么回事儿。 HTML里直接调用navigator.vibrate()会报错? 还真不是代码写错了,多半是触发的时机不对。navigator.vi
HTML里直接调用navigator.vibrate()会报错?
还真不是代码写错了,多半是触发的时机不对。navigator.vibrate()有个硬性要求——必须在用户主动操作的回调里首次登场。比如你得点一下按钮、戳一下屏幕,它才认账。你要是放在页面加载完或者setTimeout里自动执行,Chrome和Safari(iOS 16.4+)对这点抓得特别严,一旦违规,要么悄悄地返回false,要么直接甩你一个SecurityError。
实际开发里怎么绕?几个经验:
- 把震动的逻辑绑在
button的click或touchstart事件里,别往DOMContentLoaded或setTimeout里塞 - 只要成功触发过第一次,后续哪怕是在定时器或者WebSocket回调里调用,也没问题——这是一种“首触发许可”机制
- iOS Safari用户得手动去设置里开启“辅助功能→触感反馈”,而且只认固定时长(比如
[10]、[15]),别指望搞什么复杂序列

navigator.vibrate()参数怎么传才有效?
这个API的参数极其挑食——必须是数字或者数字组成的数组。你传个字符串"200"、传个对象、传个null,它倒是不会报错(返回true),但就是毫无反应,静默忽略。
常见的有效写法其实很直观:
navigator.vibrate(200)—— 震动200毫秒,单次脉冲navigator.vibrate([100, 50, 200])—— 震100ms、停50ms、再震200ms。不过注意,iOS不支持停顿,会直接合并成一次连续震动navigator.vibrate(0)或navigator.vibrate([])—— 清空当前震动队列,相当于紧急停止
值得留个心眼的细节:[0, 100]这种以0打头的数组,某些Android版本上可能会被截断,最好别这么写。
为什么安卓能震、iOS却没反应?
这是平台差异最扎心的地方。iOS对Vibration API的支持极其吝啬:iOS 16.4之后才开放,而且默认是关着的。即便你打开了,也只允许极短的脉冲(单次≤15ms,总时长≤400ms),数组里的停顿间隔?直接忽略。
开发时的兼容策略其实很清晰:
- 先检测环境:
if ("vibrate" in navigator),再识别平台:/iPad|iPhone|iPod/.test(navigator.userAgent) - 遇到iOS,统一用
navigator.vibrate(15)降级处理,别传数组 - 永远别把震动当作核心反馈手段(比如“操作成功”这种关键信息),它只能是锦上添花的增强体验,视觉和声音才是基本盘
震动反馈卡住或连震不停?
这问题常见到让人想吐槽——多数时候是因为频繁调用vibrate()却没清空队列。按钮一顿连点,或者动画循环里不停触发,Android会老老实实排队执行,iOS则可能直接撂挑子或者异常拉长时间。
稳妥的做法其实就三条:
- 每次调用前先清空队列:
navigator.vibrate(0) - 加个节流:通过
setTimeout或requestAnimationFrame控制最小间隔,建议不低于300ms - 别在
scroll、input这类高频事件里直接调震动
最后多啰嗦一句:真机测试远比模拟器靠谱。大多数浏览器的DevTools传感器模拟根本触发不了真实震动,更测不出iOS那套权限拦截逻辑。代码写对了,但设备不配合的情况,只能靠真机一一验证。
