压力感应曾经是原生应用的专属能力,但随着Pointer Events规范的推进和WebKit对Force Touch的支持,网页也可以直接读取用户的按压强度。在Mac的Force Touch触控板上用力按压,或在支持3D Touch的设备上重按屏幕,浏览器都会产生带压力数值的事件。不过并非所有设备都具备这个能力,直接绑定事件在普通设备上往往毫无反应,因此先做能力检测、再决定是否绑定压力事件,就成了实现这类交互的前置条件。本文用jQuery来组织这套逻辑,让代码结构更清晰,也方便集成到已有项目中。

一、压力事件的底层机制:pressure属性与WebKit扩展事件
理解能力检测的思路,先要弄清压力数据从哪里来。目前浏览器暴露压力信息主要有两条通道。第一条是W3C的Pointer Events规范,所有pointer类型的事件对象(pointerdown、pointermove等)都带有一个pressure属性,取值范围是0到1。需要注意的是,普通鼠标在没有压力感知的情况下,pointerdown事件的pressure通常是0.5这个固定值,这是一个很容易被忽略的坑,如果只判断pressure大于0就认定设备支持压感,几乎所有鼠标都会被误判。
第二条通道是苹果WebKit的私有扩展,主要针对MacBook的Force Touch触控板,涉及三个事件:webkitmouseforcewillbegin(按压即将开始,此时可以preventDefault阻止默认行为)、webkitmouseforce(按压过程中持续触发,事件对象包含webkitForce属性)和webkitmouseforcedown(压力超过阈值触发的强制点击)。其中webkitForce的原始数值范围大约是1到3,可以通过除以MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN(约3.0)归一化为0到1的力度系数。这套API在Safari上工作得最好,Chrome也曾支持部分能力,但不同版本差异较大,所以检测逻辑要尽量宽松,绑定逻辑要尽量防御。
二、用jQuery封装设备能力检测函数
能力检测不能只看一个条件,建议把多种信号组合起来判断。首先是特性检测:检查window.PointerEvent是否存在,以及document上是否存在webkitmouseforcewillbegin的监听支持;其次是读取设备本身的能力标识,Pointer Events 2.0规范提供了navigator.maxTouchPoints,部分实现还支持通过一个临时元素的ontouchstart推断触控能力。下面给出一个完整的jQuery封装,返回一个包含详细能力信息的对象:
(function($) {
// 检测设备是否支持压力感知(Force Touch / 3D Touch)
$.supportPressure = function() {
var result = {
pointerEvents: !!window.PointerEvent,
forceTouch: false,
maxTouchPoints: navigator.maxTouchPoints || 0
};
// 特性检测:webkitmouseforcewillbegin 是否可被监听
result.forceTouch = 'onwebkitmouseforcewillbegin' in window ||
'webkitmouseforcechanged' in window;
// 触控设备上3D Touch通常伴随多点触控能力
// 且需要 Pointer Events 提供非固定值的 pressure
result.touchPressure = result.pointerEvents && result.maxTouchPoints > 0;
return result;
};
})(jQuery);
使用时调用$.supportPressure()即可拿到各项布尔值。这里有个细节值得强调:'onwebkitmouseforcewillbegin' in window这种写法只验证了浏览器认识这个事件名,并不完全等于硬件支持压感。更严谨的做法是在首次真实交互时再做一次确认,也就是监听pointerdown事件,检查e.pressure是否出现了不等于0和0.5的数值,一旦出现就动态标记设备支持压感,这种惰性检测的准确率最高。
三、绑定压力事件并读取实时力度
检测通过后,就可以绑定具体事件了。推荐的做法是双通道并行:Pointer Events负责触屏场景,WebKit事件负责触控板场景。下面的代码演示了完整的绑定流程,包括压力归一化、按压阶段判断和事件解绑:
(function($) {
$.fn.bindPressure = function(onPressure) {
return this.each(function() {
var el = $(this);
var forceClickThreshold = 2; // webkitForce 的点击阈值参考值
// 通道一:Pointer Events(触屏 3D Touch)
el.on('pointerdown pointermove', function(e) {
if (e.originalEvent.pressure > 0 && e.originalEvent.pressure !== 0.5) {
onPressure.call(this, {
normalized: e.originalEvent.pressure,
phase: 'pressing',
source: 'pointer'
});
}
});
// 通道二:WebKit Force Touch(Mac 触控板)
el.on('webkitmouseforce', function(e) {
var evt = e.originalEvent;
var normalized = evt.webkitForce / 3; // 归一化到 0~1
onPressure.call(this, {
normalized: Math.min(normalized, 1),
phase: evt.webkitForce >= forceClickThreshold ? 'force-click' : 'pressing',
source: 'force-touch'
});
});
// 阻止触控板的默认强制点击行为(如词典预览)
el.on('webkitmouseforcewillbegin', function(e) {
e.originalEvent.preventDefault();
});
});
};
})(jQuery);
// 使用示例
$('#target').bindPressure(function(data) {
console.log('压力来源:', data.source,
'力度:', data.normalized.toFixed(2),
'阶段:', data.phase);
});
注意代码中所有原生事件属性都要通过e.originalEvent获取,因为jQuery对事件对象做了包装,压力相关的扩展属性挂在原始事件上,这是jQuery开发者最容易踩的坑之一。另外webkitmouseforcewillbegin里调用preventDefault可以阻止Safari的系统级预览行为,如果你的界面需要完全接管压力交互,这一行必不可少;反之如果希望保留系统行为,就去掉它。
四、降级策略与兼容性注意事项
压力交互本质上是一种渐进增强,绝不能让不支持的设备失去基本功能。建议的设计原则是:压力只作为快捷方式或增强反馈,点击、长按等常规交互必须独立可用。典型的降级方案是用长按模拟压力,即pointerdown后启动一个计时器,按住时间越长力度值越高,虽然损失了真实压感的细腻度,但交互语义是相通的。
还有几点兼容性提醒。第一,iOS端的Safari对Pointer Events的支持较晚,早期系统只能通过touch事件配合force属性(TouchEvent的touches数组里每个Touch对象都有force字段)获取压力,所以针对iOS要做touches[0].force的兼容读取。第二,压力事件触发频率很高,类似mousemove,回调里应避免重度的DOM操作,可以用requestAnimationFrame节流,把最新的压力值缓存起来,在动画帧里统一消费。第三,苹果逐步在移动端弱化3D Touch转向Haptic Touch,新机型上硬件压感可能不可用,所以发布前务必在真机上回归测试,不要只依赖模拟器。
把以上检测、绑定、降级三块逻辑组合起来,就能构建一套对设备差异完全免疫的压力交互层。核心思路归纳为一句话:先用能力检测守住入口,再用双通道事件覆盖不同硬件,最后用降级方案兜底,让每一类设备上的用户都能获得合理但层次不同的体验。
jQueryForce Touch3D Touch修改时间:2026-09-05 14:14:45