navigator.vibrate(150) 更可靠,因单数字参数被所有支持浏览器统一解释为持续震动,而数组模式在android兼容性差、ios完全不支持,且必须由用户手势同步触发。

为什么 navigator.vibrate(150) 比 navigator.vibrate([100, 50, 100]) 更可靠
多数 Android 设备对震动数组的支持不一致:数组长度为奇数(如 [100, 50, 100])会静默截断最后一项,变成「震 100ms →停 50ms」;部分低端机型甚至无法解析停顿间隔,直接合并为一次长震。而单数字参数(如 150)被所有支持该 API 的浏览器统一解释为“持续震动 X 毫秒”,无歧义、无兼容性陷阱。
实际开发中应优先用单数字实现关键反馈:
-
navigator.vibrate(150)适合表单提交成功、开关切换完成等需明确确认的场景 - 避免使用
[100, 50, 100]这类短节奏组合——它在 iOS 上完全无效,在部分 Android WebView 中也因总时长或项数超限被忽略 - 若真需模式震动,必须确保数组长度为偶数、总时长 ≤ 5000ms、项数 ≤ 10,且首项非 0
用户手势触发不是可选项,而是硬性前提
即使检测到 navigator.vibrate 存在且是函数,只要调用不在用户真实交互事件中同步执行,就会静默失败——控制台无报错、无警告、无任何提示。
常见失效场景包括:
- 在
setTimeout或 Promise 回调里调用(如fetch().then(() => navigator.vibrate(150))) - 放在
DOMContentLoaded或mounted钩子中初始化 - 在 iframe 内调用但未声明
allow="vibrate" - 页面处于后台标签页或被系统休眠时触发
正确写法必须绑定到用户事件处理器内,例如:
button.addEventListener('click', () => {
if ('vibrate' in navigator && typeof navigator.vibrate === 'function') {
navigator.vibrate(150);
}
});
iOS Safari 完全不支持,别白费力气检测或 fallback
'vibrate' in navigator 在 iOS Safari 中返回 true,但 typeof navigator.vibrate 是 'undefined' 或 'object'(不是函数),所以仅靠属性存在性判断会误判。更关键的是:iOS 所有版本、所有 WKWebView 场景(含微信、钉钉内嵌页)均不支持该 API,连系统级触感反馈都不走这个通道。
因此不要做这种无意义的兼容尝试:
- 不要在
else分支里加音效或动画 fallback——那属于交互设计问题,和震动 API 无关 - 不要试图用
try/catch捕获错误,它根本不会抛错 - 检测逻辑必须是:
'vibrate' in navigator && typeof navigator.vibrate === 'function'
一旦不满足,直接跳过震动逻辑,不执行、不降级、不 log。
同一时刻多次调用会被覆盖,但连续触发仍需节流
navigator.vibrate() 不排队,后一次调用会立即中断前一次。这看似省了防抖,但实际中容易出问题:
- 用户快速连点按钮,震动请求密集发出,部分设备系统会节流或丢弃
- Android 8.0+ 对震动频率有限制,高频调用可能被静默拒绝
- 某些安卓定制 ROM(如 MIUI)会在短时间内抑制重复震动
建议加轻量节流(无需完整 debounce 库):
let lastVibrateTime = 0;
const vibrate = (ms) => {
const now = Date.now();
if (now - lastVibrateTime > 50) {
navigator.vibrate(ms);
lastVibrateTime = now;
}
};
这个 50ms 间隔足够区分真实点击与误触,又不会影响操作节奏。注意:这不是为了“防止重复”,而是绕过系统底层的震动抑制策略。










