tel:链接需清洗号码并补+86前缀,URL编码+号,禁用微信内tel协议并提供复制降级方案,重置CSS样式与点击反馈。

tel: 链接必须清洗号码,否则 iOS 直接静默失败
用户输入的号码常含中文括号、空格、短横、全角标点,而 tel: 协议只接受 ^[\+\d#*]+$ 这类字符串。iOS Safari 尤其严格,tel:(138) 0013-8000 点击后无反应、无报错、控制台也看不到异常。
清洗必须做,且要放在拼接 href 前:
- 用正则提取合法字符:
number.replace(/[^+\d#*]/g, '') - 国内手机号建议统一补
+86前缀(避免 iOS 当本地号误处理) - 确保
href中冒号后**紧接**号码,不能有空格:tel:+8613800138000✅,tel: +8613800138000❌ - 若号码来自接口或变量,注意
+要 URL 编码为%2B,否则部分 Android WebView 会截断
微信里点不动?不是 bug,是默认策略
iOS 微信从 7.0.12 起彻底禁用 tel: 协议,点击无任何反馈;Android 微信需 ≥8.0.23 才支持,旧版本仍可能弹“无法打开”。这不是兼容性问题,是平台主动拦截。
检测是否在微信内:navigator.userAgent.includes('MicroMessenger')
必须提供降级方案,不能只留一个失效链接:
- 显示号码文本 + 「长按复制」提示(视觉引导)
- 绑定
touchstart事件调用document.execCommand('copy')(注意权限提示) - 禁用过时的
<meta name="format-detection" content="telephone=yes">,它已失效,且会把身份证、订单号等所有数字都转成拨号链接
a 标签样式在 iOS 和 Android 上不一致,别硬扛
iOS 默认给 a[href^="tel"] 加下划线和蓝色,Android 没这行为,导致视觉割裂。CSS 强制重置比等系统默认更可靠:
code a[href^="tel"] {
text-decoration: none;
color: inherit;
}
另外,iOS 点击延迟明显,可加:
-
style="touch-action: manipulation;"减少响应延迟 - 点击后立即禁用:加 class 或设
pointer-events: none,防止连点(tel:不触发click,防不住只能 UI 层压制)
别试图监听拨号结果,协议本身就不支持
tel: 是原生 URI Scheme,跳转即离开当前页面上下文,不触发 click、beforeunload,也无法 preventDefault。所谓“判断是否拨出”,目前只有两种间接方式:
- 监听
visibilitychange(页面切到后台 → 可能唤起拨号盘,但不可靠,iOS 微信根本不会触发) - 用
touchstart + setTimeout猜测(300ms 内没触发visibilitychange就当失败,误差大)
真正关键的不是“怎么知道拨没拨”,而是“用户点下去之后,有没有明确反馈、有没有可用 fallback”。这点容易被忽略,但恰恰决定体验是否断裂。

















