在 v3.10.0 中新增
Observer
快速入门
CDN 链接
gsap.registerPlugin(Observer)
最简用法
Observer.create({
target: window, // can be any element (selector text is fine)
type: "wheel,touch", // comma-delimited list of what to listen for
onUp: () => previous(),
onDown: () => next(),
});
一种超级灵活、统一的方式来感知所有(触摸/鼠标/指针)设备上的有意义事件,而无需纠结于各种实现细节。也许您希望响应“类似滚动”的用户行为,这可能是一个鼠标滚轮旋转、手指在触摸设备上滑动、拖动滚动条,或指针按下并拖动……当然您需要方向数据和速度信息。没问题!
告诉 Observer 要监听哪些事件类型(wheel、touch、pointer 和/或 scroll),它将在每个 requestAnimationFrame tick 期间收集 delta 值(默认情况下为了性能会进行防抖处理),并自动确定最大的 delta,然后触发相应的回调函数,如等等(详见下面的完整列表)。防抖处理。由于 ScrollTrigger 的onUp
, onDown
, onDrag
,等等(见下文完整列表)。
看看基于用户向上/向下滑动或使用鼠标滚轮时触发 next()/previous() 函数有多么简单:
Observer.create({
target: window, // can be any element (selector text is fine)
type: "wheel,touch", // comma-delimited list of what to listen for ("wheel,touch,scroll,pointer")
onUp: () => previous(),
onDown: () => next(),
});
Observer 也包含在 ScrollTrigger 中!
这里还有一个ScrollTrigger.observe()方法,其作用与Observer.create()
完全相同。由于 ScrollTrigger 的normalizeScroll()功能在底层使用了 Observer(因此它已经包含在 ScrollTrigger 中),公开它的功能是有意义的,这样如果您已经在项目中使用了 ScrollTrigger,就可以避免将 Observer 作为单独的文件加载。不客气。🙂
演示
注意下面的演示中实际上没有滚动,但您可以使用鼠标滚轮(或者在触摸设备上滑动)来启动移动,使其“感觉”像在滚动:
加载中...
- 丰富的回调系统包括 onDown、onUp、onLeft、onRight、onDrag、onDragStart、onDragEnd、onHover、onHoverEnd、onToggleY、onToggleX、onChangeX、onChangeY、onChange、onClick、onPress、onRelease、onMove、onWheel 以及 onStop
- 默认情况下为了最佳性能进行了防抖处理(你可以设置 by default for maximum performance (you can set
debounce: false
如果需要的话) - 跨浏览器兼容— 自动判断应使用 TouchEvents、PointerEvents 还是 MouseEvents。
- 自动优先选择具有最大delta 的事件(例如,在同一个防抖时间段内同时发生了 wheel、scroll 和 touch 事件)
阅读更多...
- 忽略某些元素,比如
ignore: ".deadzone"
- 获取速度(分别在 x 轴和 y 轴方向)以及 clientX 和 clientY 坐标(用于 touch/pointer 事件)
- 设置一个拖拽的最小阈值. For example, dragMinimum: 5 would only fire the onDragStart/onDrag/onDragEnd callbacks if the user moved 5 pixels or more.
- 设置一个tolerance,以便仅当达到最小 delta 时才触发运动相关回调。例如,tolerance: 50 表示只有当变化至少为 50 像素时才开始触发回调,一旦达到该值后重新开始计数。
tolerance: 50
would wait until there has been a change of at least 50 pixels, and then once that's reached it starts over. - 设置一个wheelSpeed乘数因子,如果你希望调整 wheel 相关的 delta 值(加快或减慢)。
- 与 GSAP 集成,并且ScrollTrigger
- 大约压缩后 3.5KB
配置对象
传递给Observer.create()
的配置对象可以包含以下任意可选属性:
- 字符串— 当
lockAxis: true
被设置时,每次按压后的首次拖拽动作(类型为 "pointer" 和/或 "touch")将根据用户移动的方向设置axis
属性为 "x" 或 "y"。你可以使用onLockAxis()
回调来知道何时被设置。 - Boolean- 如果设置为
true
,这会让 touch/pointer 相关的监听器使用捕获阶段。类似于执行 addEventListener("[type]", func, {capture: true}); - Boolean— 默认情况下,Observer 会对事件进行防抖处理,以便在每个 requestAnimationFrame() tick 期间累积 delta 值以提高性能,但你可以通过
debounce: false
来禁用该项功能。在这种情况下,它会在每个事件上立即检查。防抖会影响除onPress
,onRelease
,onHover
,onHoverEnd
,onClick
,onDragStart
,以及onDragEnd
之外的所有回调,因为这些回调与 delta 无关。 - 数字— 被视为“拖拽”所需的最小距离(以像素为单位)。这有助于防止特别是在触摸设备上微小动作被误认为有明确意图。例如,仅用手指按下手机屏幕可能会注册出几个像素的轻微移动,尽管用户认为自己的手指是静止的。dragMinimum 仅适用于按下后的初始移动,之后继续拖拽只会受到 "tolerance" 的节流控制。
- 元素 | 字符串 | 数组— 你希望 observer忽略的元素,当这些元素触发了一个 scroll/touch/pointer/mouse 事件时,整个事件将被完全忽略。它会检查事件的目标来决定是否忽略。你可以将
event.target
定义为一个 Element 引用、类似ignore
的选择器文本,或者一个元素数组(数量不限)。".ignore-me"
, or an Array of elements (it can be as many as you'd like). - Boolean- 如果设置为
true
,Observer 将会在每次按压后首次拖拽移动时(类型为 "pointer" 和/或 "touch")检测方向,并锁定到该方向直到用户释放指针/触摸。因此,如果首次拖拽是水平方向,则只会有像onChangeX()
这样与水平相关的回调被触发直到指针/触摸释放。甚至还有一个onLockAxis()
回调供你绑定。 - 函数— 当在任一y轴(垂直方向)或者x轴(水平方向)检测到移动时调用的函数。只要移动持续就会不断调用该函数(受任何 tolerance 阈值限制)。
- 函数— 当在 x 轴(水平方向)检测到移动时调用的函数。只要移动持续就会不断调用该函数(受任何 tolerance 阈值限制)。
- 函数— 当在 y 轴(垂直方向)检测到移动时调用的函数。只要移动持续就会不断调用该函数(受任何 tolerance 阈值限制)。
- 函数— 当目标被点击时调用的函数。
- 函数— 当检测到向下的运动时调用的函数,这意味着 delta 值增加(比如你的手指/鼠标向下拖动…使得
y
坐标增加)。如果你想仅反转鼠标滚轮的 delta,你可以设置wheelSpeed: -1
因为它是一个乘数。 - 函数— 当用户按下目标并开始拖动时调用的函数(受
dragMinimum
限制)。这只适用于 "touch" 和/或 "pointer" 类型。 - 函数- 用户移动指针/触摸/鼠标时调用的函数在按下时在目标元素上(仅适用于"touch"和/或"pointer"类型)。
- 函数- 用户停止在目标元素上拖动时调用的函数(仅适用于"touch"和/或"pointer"类型)。
- 函数- 检测到向左方向移动时调用的函数。
- 函数- 当轴锁定时调用的函数(需要
lockAxis: true
)。可以通过观察器的axis
属性("x"或"y")检查是哪个轴。 - 函数- 指针/鼠标悬停在目标上时调用的函数("pointerenter"/"mouseenter"事件)。
- 函数- 指针/鼠标移出目标时调用的函数("pointerleave"/"mouseleave"事件)。
- 函数- 用户在悬停于目标元素上时移动指针/鼠标时调用的函数(仅适用于"pointer"类型)。它内部监听"pointermove"/"mousemove"事件。如果您希望只在按下并拖动时触发,请使用
onDrag
如果您想让它仅在按压和拖动时触发。需要注意的是,当您定义onMove时,它会导致观察者在悬停期间测量delta值悬停期间在目标上方,从而触发适当的与移动相关的回调函数,如onUp、onDown、onChange等,以响应在目标上方的任何指针/鼠标移动。通常情况下,与移动相关的回调函数只有在用户按下并拖动时才会被触发. - 函数- 用户按下目标元素时调用的函数(仅适用于"touch"和/或"pointer"类型)。
- 函数- 调用
onPress
后释放触摸/指针时调用的函数(仅适用于"touch"和/或"pointer"类型)。 - 函数- 检测到向右方向移动时调用的函数。
- 函数- 当变化停止至少0.25秒时调用的函数(可通过
onStopDelay
) - 数字- 变化停止后等待多少秒才调用
onStop
的时间(默认:0.25秒)。 - 函数- 移动切换方向时调用的函数在x轴上(水平方向)。
- 函数- 移动切换方向时调用的函数在y轴上(垂直方向)。
- 函数- 检测到向上运动时调用的函数,意味着delta值减少(比如手指/鼠标向上滑动...这使得
y
坐标减少)。如果您只想反转鼠标滚轮delta值,可以设置wheelSpeed: -1
因为它是一个乘数。 - 函数- 鼠标滚轮使用时调用的函数。
- 数字- 滚动delta值的乘数。这仅适用于
"scroll"
类型,意思是当目标分派一个不同于滚轮事件的滚动事件时。您可以设置scrollSpeed: -1
来反转delta值,并使其调用onUp
而不是onDown
(反之亦然)。scrollSpeed: 0.5
将使delta值变为一半通常情况下的数值。注意:还有一个单独的wheelSpeed
选项,仅适用于滚轮事件。 - 元素 | 字符串- 应该监听事件的元素。默认情况下,它是主视口。
- 数字- 触发其中一个回调(如
onUp
,onDown
,onChangeY
等)所需的最小距离(以像素为单位)。例如,如果容差是10但用户只移动了8个像素,则不会触发回调。一旦距离超过容差量,就会触发回调并重置,再次等待该距离被超过之后才会再次触发回调。 - 字符串- 包含您想要监听的动作类型的逗号分隔列表,可以包含以下内容中的任意一个(或全部):
"wheel,touch,scroll,pointer"
。 "touch"适用于任何触控设备,无论浏览器如何(iOS/Android可能在底层使用TouchEvent,而微软可能使用PointerEvent,但Observer将它们都包括在"touch"中)。 "pointer"涵盖所有非触控的指针/鼠标按下/拖动/滑动动作。"wheel"用于鼠标滚轮移动,"scroll"用于滚动事件。默认是"wheel,touch,pointer"
- 数字- 滚轮delta值的乘数。默认情况下,它只是传递浏览器报告的滚轮事件delta值,但可能看起来比使用指针按下/拖动时更快/更慢,您需要一种方法使它们更相似。例如,为了使滚轮delta值变成正常值的一半,您可以设置
wheelSpeed: 0.5
。您可以设置wheelSpeed: -1
来反转delta值,并使其调用onUp
而不是onDown
(反之亦然)。注意:还有一个单独的scrollSpeed
选项,仅适用于滚动事件。
属性
描述
回调数据
每个回调都会接收到观察者实例本身作为唯一的参数,以便您可以轻松访问诸如self.velocityX
, self.velocityY
, self.deltaX
, self.deltaY
, self.x
, self.y
等数据(请参阅左侧边栏了解所有可用属性的列表),例如:
Observer.create({
...
onChange: (self) => {
console.log("velocity:", self.velocityX, self.velocityY, "delta:", self.deltaX, self.deltaY, "target element:", self.target, "last event:", self.event);
}
});
导航栏左侧有属性列表。
展示及教程演示
属性
deltaX: 数值 | 自上次在此轴上触发回调以来的水平变化量(以像素为单位)。例如, |
deltaY: 数值 | 自上次在此轴上触发回调以来的垂直变化量(以像素为单位)。例如, |
event: 事件 | 最近的事件对象(可能是TouchEvent、PointerEvent、MouseEvent、WheelEvent或ScrollEvent,具体取决于您定义的 |
isDragging:布尔值 | 当用户按下 |
isEnabled:布尔值 | 指示观察者是否启用。使用 |
isPressed:布尔值 | 设为 |
startX: 数值 | 这个 |
startY: 数值 | 这个 |
Observer.isTouch: 数值 | 一种区分当前设备触控能力的方式 — |
目标对象: Element | 目标元素 |
vars: 对象 | 最初传递给 Observer.create() 的配置对象。 |
velocityX: 数值 | 水平速度(单位为像素每秒)。 |
velocityY: 数值 | 垂直速度(单位为像素每秒)。 |
x: 数值 | 垂直位置 |
y: 数值 | 垂直位置 |
方法
disable( ) : void | 禁用观察者,移除必要的事件监听器,并在观察者尚未禁用的情况下触发 |
enable( event:Event ) : Self | 启用观察者,添加必要的事件监听器,并在观察者尚未启用的情况下触发 |
kill( ) : void | 销毁观察者实例,调用 |
Observer.create( vars:Object ) : Observer | 根据提供的配置详细信息创建一个新的 Observer 实例。 |
Observer.getAll( ) : 数组 | 获取所有已创建(并且未销毁)的观察者数组。例如,如果您的框架要求您在路由更改时销毁所有内容,则此方法可能会很有用。 |
Observer.getById( id:String ) : Observer | 具有匹配 |
常见问题
可以将多个 Observer 实例应用到同一个目标吗?
当然可以!例如,当您希望某些回调去抖动而其他不进行去抖动时,这将很有用。请记住,您可以随时 .disable() 和 .enable() 观察者。
如果我已经加载了 ScrollTrigger,是否还需要额外加载 Observer?
不需要,Observer 已经包含在 ScrollTrigger 文件中;你可以通过ScrollTrigger.observe()访问它并跳过单独加载 Observer 文件。
示例演示
查看完整系列的使用演示和我们最喜欢的社区灵感演示在 CodePen 上。
Observer 示例