Draggable
快速入门
CDN 链接
gsap.registerPlugin(Draggable)
最简用法
Draggable.create("#yourID", {
type: "x",
});
提供一种出人意料的简便方式,可以使用鼠标和/或触摸事件使几乎任何 DOM 元素具有可拖拽、旋转、抛掷甚至轻弹滚动的功能。
Draggable 与InertiaPlugin完美集成,因此用户可以轻拂并让动作根据惯性平滑减速。
加载中...
特性
- 支持触摸- 在平板电脑、手机和桌面浏览器上都能很好地工作。
- 极其流畅- GPU 加速和
requestAnimationFrame
-驱动以获得最佳性能。与其他选项相比,Draggable 显得更加自然流畅,尤其是在施加边界限制和动量效果时。 - 基于动量的动画- 如果您加载了 InertiaPlugin,只需设置
inertia: true
在config
对象,它会在鼠标/触摸释放后自动应用自然的基于动量的运动,使对象优雅地滑行至停止。您甚至可以控制resistance
的数量,以及最大或最小duration
,等等。
阅读更多...
- 施加边界限制- 告诉一个可拖拽元素保持在另一个 DOM 元素(容器)的范围内,例如:
bounds: "#container"
或者将边界定义为坐标形式,例如:bounds: {top: 100, left: 0, width: 1000, height: 800}
或者指定具体的最大值和最小值,例如:bounds: {minRotation: 0, maxRotation: 270}
. - 检测与其它元素重叠
hitTest()
- 判断一个元素是否与另一个元素重叠,甚至可以设定容差阈值(比如至少 20 像素或者任一元素总表面积的 25%),使用功能强大的Draggable.hitTest()
方法。传入一个鼠标事件,它会告诉您鼠标是否在该元素之上。参见这个 CodePen获取一个简单示例。 - 定义触发元素- 也许您只想让某个特定区域触发拖拽操作(比如窗口的顶部栏)- 这非常简单,比如使用
trigger: "#topBar"
即可。 - **拖拽位置或旋转** - 可选择多种拖拽类型:[
"x,y"
|"top,left"
|"rotation"
|"x"
|"y"
|"top"
|"left"
] - 锁定沿特定轴的移动- 设置
lockAxis: true
Draggable 将检测用户开始拖拽的方向,并随后将其限制在该轴上。如果您只想允许垂直或水平移动,可以使用类型参数 ("top"
或者"y"
仅允许垂直移动;"x"
,或者"left"
仅允许水平移动)。 - 旋转尊重变换原点- 默认情况下,可旋转元素将围绕其中心点旋转,但您可以设置
transformOrigin
为其他值来更改旋转中心点。例如,若在拖拽前调用gsap.set(yourElement, {transformOrigin: "top left"})
,则它将围绕其左上角旋转。或者使用%
或者px
。元素 CSS 中设置的任何值都将被保留。 - 丰富的回调系统和事件分发机制- 您可以使用以下任意回调:
onPress
,onDragStart
,onDrag
,onDragEnd
,onRelease
,onLockAxis
,以及onClick
。在这些回调中,this
指向 Draggable 实例本身,因此您可以轻松访问它的target
或者bounds
等等属性。如果您更倾向于使用事件监听器,Draggable 同样支持事件分发,所以可以执行类似yourDraggable.addEventListener("dragend", yourFunc);
- 的操作。与 SVG 配合很好。
- 甚至可以在变换后的容器中正常运行!- 拖拽对象位于经过旋转或缩放的容器中?没问题。我们所见到的其他工具都无法正确处理这种情况。
- 自动滚动,甚至可在多个容器中同时滚动。- 设置
autoScroll: 1
进行正常速度的自动滚动,或者设置autoScroll: 2
进行两倍速度的滚动等等。越靠近边缘,滚动速度越快。请参见示例:此处. - 当元素移动距离小于 3 像素时检测点击行为- 一个常见的难题是判断用户是在尝试点击或轻触对象而不是拖拽它。如果鼠标/触摸从初始位置移动的距离小于 3 像素,则会被解释为点击,此时将调用
onClick
回调函数(并分发一个"click"
事件),而不会实际移动元素。您可以通过设置minimumMovement
配置属性来定义不同的阈值,例如minimumMovement: 6
表示 6 像素。
用法
最简单的形式下,您可以像这样使一个元素具有拖拽功能(包括横向和纵向):
Draggable.create("#yourID");
这段代码将查找 ID 为"yourID"
的元素,并使其可拖拽,不设边界,也没有释放后动能效果。您也不必使用选择器字符串——您可以直接传入元素本身,甚至是一个对象数组。
使用vars
参数用于定义各种配置选项。例如,要让对象只在使用y
transform 的情况下进行垂直滚动,并限制在其 ID 为"container"
的 DOM 元素范围内,并在点击时调用一个函数,在拖拽结束时调用另一个函数,并且让它具有基于动量的运动效果(前提是你加载了 InertiaPlugin),可以这样做:
Draggable.create("#yourID", {
type: "y",
bounds: document.getElementById("container"),
inertia: true,
onClick: function () {
console.log("clicked");
},
onDragEnd: function () {
console.log("drag ended");
},
});
或者要实现某物可旋转(拖拽时旋转元素),您可以简单地这样做:
Draggable.create("#yourID", {
type: "rotation",
inertia: true,
});
并添加在释放鼠标/触摸后对齐到 90 度增量的功能(如每次轻扫旋转都会停在 90 度的倍数位置),使用 snap 选项:
Draggable.create("#yourID", {
type: "rotation",
inertia: true,
snap: function (value) {
//this function gets called by InertiaPlugin when the mouse/finger is released and it plots where rotation
//should normally end and we can alter that value and return a new one instead. This gives us an easy way to
//apply custom snapping behavior with any logic we want. In this case, we'll just make sure the end value snaps
//to 90-degree increments but only when the "snap" checkbox is selected.
return Math.round(value / 90) * 90;
},
});
配置对象
- 字符串- 指针按下到释放期间应该使用的光标 CSS 值。它可以与普通的
cursor
值,例如:cursor: "grab", activeCursor: "grabbing"
. - Boolean- 如果
true
,Draggable 将允许上下文菜单(比如用户右键点击或长按)。通常情况下这是被抑制的,因为它可能会妨碍拖动(尤其是在触摸设备上)。默认值:false
. - Boolean- 如果
true
,preventDefault()
不会在原始的鼠标/指针/触摸事件上调用。如果你希望允许默认行为(如触摸滚动),这可能很有用。然而通常来说,最好让 Draggable 调用preventDefault()
以获得最佳的拖拽用户体验。默认值:false
. - Boolean- 默认情况下,当 Draggables 限制为单一轴时,允许在相反方向进行原生触摸滚动。例如,一个
type: "x"
或者"left"
的 Draggable 允许垂直方向的原生触摸滚动,type: "y"
或者"top"
则允许水平方向的原生触摸滚动。默认值:true
. - 数字- 要启用当 Draggable 被拖动到可滚动容器边缘40像素以内时自动滚动,请将 autoScroll 设置为非零值,其中1表示正常速度,2表示双倍速度,依此类推(可以使用任意数字)。为了更直观或自然的效果,当鼠标/触摸越靠近边缘时会滚动得越快。默认值为0(不自动滚动)。请参阅这个 CodePen查看演示。
- [元素 | 字符串 | 对象]- 要使可拖动元素保持在另一个 DOM 元素(如容器)的边界内,你可以传入该元素,例如
bounds: document.getElementById("container")
或者甚至传入选择器文本如"#container"
。如果愿意,你也可以将边界定义为矩形,例如bounds: {top: 100, left: 0, width: 1000, height: 800}
它基于父级的坐标系统(top 和 left 是相对于父级左上角的位置)。或者你可以定义特定的最大和最小值,如bounds: {minX: 10, maxX: 300, minY: 50, maxY: 500}
或者bounds: {minRotation: 0, maxRotation: 270}
. - 对象- 所有回调函数(
onDrag
,onDragEnd
,onDragStart
等等)所使用的执行作用域。这个作用域决定了在任何回调函数中this
指向的对象。较旧的针对每个回调的作用域属性已被弃用但仍有效。 - 函数- 你的 Draggable 可能包含一些“可点击”的子元素,例如链接
<a>
标签,<button/>
或者<input>
元素等等。默认情况下,它对这些元素上的点击和轻触会有不同的处理方式,不允许用户拖动它们。你可以设置dragClickables: true
来覆盖此行为,但有时你可能还是想精确控制 Draggable 认为哪些元素是“可点击”的。因此你可以使用自定义函数,该函数接收被点击的元素作为唯一的参数,并返回 true 或 false。每当用户按下鼠标或手指在 Draggable 上时,Draggable 都会调用这个函数,并将事件的目标传递给你的 clickableTest 函数。 - 字符串- 默认情况下(除了
type: "rotation"
外),元素的 cursor CSS 属性会被设置为move
这样当鼠标悬停其上时会有视觉提示表明它可以移动。但你也可以根据需要定义不同的光标(如文档描述于https://devdocs.io/css/cursor)例如cursor: "pointer"
. - Boolean- 默认情况下,Draggable 可以应用于几乎所有元素,但有时你可能希望点击
<a>
,<input>
,<select>
,<button>
,以及<textarea>
元素(以及任何具有data-clickable="true"
属性的元素)不会触发拖动操作,这样浏览器的默认行为才会生效(例如点击输入框会获得焦点并放置光标以便开始输入)。如果你想让 Draggable 忽略这些点击并允许默认行为,则设置dragClickables: false
. - 数字- 一个介于0和1之间的数值,用于控制在拖动过程中持续施加到元素上的阻力大小。1 表示完全不允许拖动,0.75 表示较大阻力(使对象以四分之一速度移动),0.5 表示半速等等。这个设置甚至可以应用于旋转。
- 数字- 一个介于0和1之间的数值,用于控制当元素超出边界(如果有设置边界的话)时所受到的阻力大小。1 表示完全不允许拖出边界,0.75 表示较大阻力(拖动时对象在边界外以四分之一速度移动),0.5 表示半速等等。这个设置甚至可以应用于旋转。
- Boolean- 默认情况下,当浏览器支持时,会使用3D变换来强制将元素置于GPU自己的图层上,从而加快合成速度。通常这种做法性能最佳,但你可以通过设置
force3D: false
来禁用它。如果你正在拖动的元素包含正在动画的子元素,那么这样做可能是明智的选择。 - [Boolean | 对象]- InertiaPlugin 是在用户释放鼠标(或触摸)后实现基于动量运动的关键。要让 Draggable 在鼠标释放(或触摸结束)时自动对该元素应用一个 InertiaPlugin 动画,你可以设置
inertia: true
(inertia
也适用)。或者,对于高级效果,你可以定义实际的惯性对象,它会被传递到 tween 中,例如inertia: {top: {min: 0, max: 1000, end: [0,200,400,600]}}
。不过,如果你想要对 InertiaPlugin 动画进行完全控制,你可以简单地使用onDragEnd
调用你自己的函数来创建动画。如果定义了inertia: true
,你还可以使用以下适用于鼠标/触摸释放后运动的配置属性...查看更多详细信息
- snap: [函数 | 对象 | 数组] - 允许你定义规则,指定元素在释放后应该落脚在哪里。例如,你可能希望旋转总是停在90度的增量位置上,或者你希望
x
和y
希望值正好落在网格上(自然落点最近的格子),或者你可能希望它落在一个非常特定的值上。你可以通过以下任何一种方式定义这个对齐规则:- 作为一个函数- 这个函数会接收到一个数值参数,即自然结束的值。该函数必须返回新的结束值(你可以在函数内部运行任意逻辑并返回对应的值)。例如,要使值对齐到最接近的50的倍数,你可以这样做:
snap: function(endValue) { return Math.round(endValue / 50) * 50; }
. - 作为一个数组- 如果使用一组数值,InertiaPlugin 首先会计算自然落点,然后遍历数组并找出最接近的数字(只要它不在你定义的边界之外)。例如,从中选择最接近的10、50、200和450中的数值时,你可以这样做:
snap: [10,50,200,450]
. - 作为一个对象- 如果你希望对每个属性使用不同的逻辑,比如如果
type
设置为"x,y"
并且你希望x
部分对齐到一组特定的值,y
部分对齐到另一组值,你可以使用具有对应属性的对象,例如:snap:{x: [5,20,80,400], y: [10,60,80,500]}
或者如果type
设置为"top,left"
并且你想分别为其使用不同的函数,你可以这样写:snap: {top: function(endValue) { return Math.round(endValue / 50) * 50; }, left: function(endValue) { return Math.round(endValue / 100) * 100; }}
。你可以在该对象中定义一个 points 属性,将两者结合在一起:x
和y
,例如liveSnap: {points: [{x: 0, y: 0},{x: 100, y: 0}], radius: 20}
当该点在数组中距离在20像素(distance)以内时会自动贴靠到数组中的任意一点。或者你甚至可以使用基于函数的值来运行你自己的贴靠逻辑,例如:liveSnap: {points: function(point) { //run custom logic and return a new point }}
。有关示例,请参见本页的贴靠(snapping)部分。
- 作为一个函数- 这个函数会接收到一个数值参数,即自然结束的值。该函数必须返回新的结束值(你可以在函数内部运行任意逻辑并返回对应的值)。例如,要使值对齐到最接近的50的倍数,你可以这样做:
- onThrowUpdate : 函数- 每次 InertiaPlugin 的补间动画更新/渲染时调用的函数(基本上相当于每次引擎“tick”时激活补间动画)。这仅适用于用户释放鼠标/触摸后生成的补间动画 —— 在用户拖动元素时不会调用该函数(那是由
onDrag
控制的)。默认情况下,onThrowUpdate
的作用域是 Draggable 实例本身,但如果你更愿意,也可以定义一个callbackScope
,就像其他补间动画一样。 - onThrowComplete : 函数- 当 InertiaPlugin 补间动画完成时调用的一个函数。这仅适用于用户释放鼠标/触摸后生成的补间动画 —— 用户释放鼠标/触摸时并不会立即调用该函数 —— 那是由
onDragEnd
控制的。默认情况下,onThrowComplete
的作用域是 Draggable 实例本身,但如果你更愿意,也可以定义一个callbackScope
,就像其他补间动画一样。 - throwResistance : 数字- 一个数值(
1000
默认值)用于控制当鼠标/触摸释放并且启用了基于动量的运动(通过设置inertia: true
参数)时的阻力或摩擦力。数值越大,阻力越强,运动减速得越快。(需要 InertiaPlugin 和设置inertia: true
,否则throwResistance
会被忽略。) - maxDuration : 数字- 基于动能的惯性补间动画的最大持续时间(以秒为单位)。InertiaPlugin 会自动分析速度和边界,并确定合适的持续时间(通常更快的动作会导致更长的缓动时间),但你可以通过定义一个
maxDuration
来设置上限。默认值为10秒。这与用户拖动物体的最长时间无关 —— 它只针对释放鼠标/触摸后出现的惯性补间动画。(需要 InertiaPlugin 和设置inertia: true
,否则maxDuration
会被忽略。) - minDuration : 数字- 基于动能的惯性补间动画应保持的最小持续时间(以秒为单位)。InertiaPlugin 会自动分析速度和边界,并确定合适的持续时间(通常更快的动作会导致更长的缓动时间),但你可以强制让补间至少持续一段时间,通过定义一个
minDuration
默认值为0.2秒。这与用户拖动物体的最短时间无关 —— 它只针对释放鼠标/触摸后出现的惯性补间动画。(需要 InertiaPlugin 和设置inertia: true
,否则 minDuration 会被忽略。) - overshootTolerance : 数字- 影响在补间结束时平稳返回静止位置之前允许超出多少范围。当快速滑动产生的初始速度超过边界/min/max时可能会发生这种情况。数值越大,
overshootTolerance
允许补间在必要时超越最大/最小值的余地就越大。默认值为1
如果你不希望有任何超出,可以将其设为0
.
- snap: [函数 | 对象 | 数组] - 允许你定义规则,指定元素在释放后应该落脚在哪里。例如,你可能希望旋转总是停在90度的增量位置上,或者你希望
- [函数 | Boolean | 数组 | 对象]- 允许你定义一些规则,在拖动过程中 the element is being dragged (whereas regular snap affects only the end value(s), where the element lands after the drag is released). For example, maybe you want the rotation to snap to 10-degree increments while dragging or you want the x and y values to snap to a grid (whichever cell is closest). You can define the
liveSnap
in any of the following ways:查看更多详细信息
- 作为一个函数- 这个函数会接收到一个数值参数,即原始的(未修改的)值。该函数必须返回新的值(你可以在函数内部运行任意逻辑并返回对应的值)。例如,要使值对齐到最接近的50的倍数,你可以这样做:
liveSnap: function(value) { return Math.round(value / 50) * 50; }
. - 作为一个数组- 如果你使用一组数值,Draggable 会遍历数组并找到最接近的数字(只要它不在你定义的边界之外)。例如,从中选择最接近的10、50、200和450中的数值时,你可以这样做:
liveSnap: [10,50,200,450]
. - 作为一个对象- 如果你希望对每个属性使用不同的逻辑,比如如果
type
设置为"x,y"
并且你希望“x”部分贴靠到一组值,而“y”部分贴靠到另一组值,你可以使用一个具有对应属性的对象,例如:liveSnap: {x: [5,20,80,400], y: [10,60,80,500]}
。或者如果type
设置为"top,left"
并且你想为每个属性使用不同的函数,你可以这样做:liveSnap: {top: function(value) { return Math.round(value / 50) * 50; }, left: function(value) { return Math.round(value / 100) * 100; }}
。你可以在此对象内定义一个points
属性,将x和y组合在一起,比如liveSnap: {points:[{x: 0, y: 0}, {x: 100, y: 0}], radius: 20}
当该点在数组中距离在20像素(distance)以内时会自动贴靠到数组中的任意一点。或者你甚至可以使用基于函数的值来运行你自己的贴靠逻辑,例如:liveSnap: {points: function(point) { //run custom logic and return a new point }}
。有关示例,请参见本页的贴靠(snapping)部分。 - 作为布尔值(
true
)- 实时贴靠(live snapping)将使用为snap
定义的所有内容(这样不仅适用于最终值,也适用于拖拽过程中的实时应用)。
- 作为一个函数- 这个函数会接收到一个数值参数,即原始的(未修改的)值。该函数必须返回新的值(你可以在函数内部运行任意逻辑并返回对应的值)。例如,要使值对齐到最接近的50的倍数,你可以这样做:
- Boolean- 如果
true
,当在任一方向(水平或垂直)上拖动超过2像素时,将锁定移动到该轴向,因此在此次拖拽过程中元素只能沿该方向(水平或垂直,以初始移动最大的方向为准)拖动。不允许对角线移动。显然,这仅适用于类型为type
id 为"x,y"
,或者"top,left"
的可拖拽元素。如果你只允许垂直移动,应设置type
设置为"y"
或者"top"
。如果你只允许水平移动,应设置type
设置为"x"
或者"left"
. - 数字- 默认情况下,Draggable要求可拖拽元素必须移动超过2像素才会被解释为拖拽操作,但你可以使用
minimumMovement
。所以minimumMovement: 6
则要求可拖拽元素移动超过6像素才被视为拖拽操作。 - 函数- 当鼠标/触摸按下并释放时,在没有移动3个像素或更多的情况下调用的函数。这使得更容易判断用户的意图(点击或拖动)。在此函数中,
this
指向 Draggable 实例(除非你明确指定了使用callbackScope
设置的作用域),this.target
) 或者边界坐标 (this.maxX
,this.minX
,this.maxY
,以及this.minY
). 默认情况下,pointerEvent
(与 Draggable 相关的最后的鼠标或触摸事件)将作为唯一的参数传递给回调函数,这样你可以例如访问它的pageX
,pageY
,target
,currentTarget
,等等。 - 数组- 提供给
onClick
回调函数的可选参数数组。例如,onClickParams: ["clicked", 5]
可以与此代码一起使用:onClick: function(message, num) { console.log("message: " + message + ", num: " + num); }
. - 函数- 在每次拖拽期间鼠标(或触摸)移动时调用的函数。在这个函数中,
this
指向 Draggable 实例(除非你明确指定了使用callbackScope
设置的作用域),this.target
) 或者边界坐标 (this.maxX
,this.minX
,this.maxY
,以及this.minY
). 默认情况下,pointerEvent
(与 Draggable 相关的最后的鼠标或触摸事件)将作为唯一的参数传递给回调函数,这样你可以例如访问它的pageX
,pageY
,target
,currentTarget
等等。这个回调每requestAnimationFrame只调用一次。 - 数组- 提供给
onDrag
回调函数的可选参数数组。例如,onDragParams: ["dragged", 5]
可以与此代码一起使用:onDrag: function(message, num) { console.log("message: " + message + ", num: " + num); }
. - 函数- 一旦鼠标(或触摸)在拖拽后松开时立即调用的函数。即使没有任何移动,
onDragEnd
总是会被触发,而onClick
回调只有在鼠标/触摸移动小于3像素时才会触发。在这个函数中,this
指向 Draggable 实例(除非你明确指定了使用callbackScope
设置的作用域),this.target
) 或者边界坐标 (this.maxX
,this.minX
,this.maxY
,以及this.minY
). 默认情况下,pointerEvent
(最后一个与 Draggable 相关的鼠标或触摸事件)将作为唯一参数传递给回调,这样您可以例如访问pageX
,pageY
,target
,currentTarget
,等等。 - 数组- 提供给
onDragEnd
回调函数的可选参数数组。例如,onDragEndParams: ["drag ended", 5]
可以与此代码一起使用:onDragEnd: function(message, num) { console.log("message: " + message + ", num: " + num); }
. - 函数- 一旦鼠标(或触摸)移动超过2像素就调用的函数,意味着拖拽已经开始。在这个函数中,
this
指向 Draggable 实例(除非你明确指定了使用callbackScope
设置的作用域),this.target
) 或者边界坐标 (this.maxX
,this.minX
,this.maxY
,以及this.minY
). 默认情况下,pointerEvent
(最后一个与 Draggable 相关的鼠标或触摸事件)将作为唯一参数传递给回调,这样您可以例如访问pageX
,pageY
,target
,currentTarget
,等等。 - 数组- 提供给
onDragStart
回调函数的可选参数数组。例如,onDragStartParams: ["drag started", 5]
可以与此代码一起使用:onDragStart: function(message, num) { console.log("message: " + message + ", num: " + num); }
. - 函数- 一旦移动被锁定到水平或垂直轴时调用的函数。这种情况发生在
lockAxis
设置为true
并且用户拖动足够远的距离让Draggable判定锁定了哪个轴时。在启用了触摸的设备上,当你有一个仅允许沿一个轴拖动(如type: "x"
,type: "y"
,type: "left"
,或者type: "top"
)的Draggable,并且用户通过触摸进行拖动时,Draggable也会判断方向,从而决定是否允许原生触摸滚动还是由Draggable驱动的拖动。在函数内部,this
指向Draggable实例,便于访问锁定的轴向(this.lockedAxis
其值为"x"
或者"y"
),或目标元素(this.target
),等等。默认情况下,最新的与Draggable相关的鼠标或触摸事件(pointerEvent
(最后一个与 Draggable 相关的鼠标或触摸事件)将作为唯一参数传递给回调,这样您可以例如访问pageX
,pageY
,target
,currentTarget
,等等。 - 函数- 在每次拖拽期间鼠标(或触摸)移动时调用的函数。在这个函数中,
this
指向 Draggable 实例(除非你明确指定了使用callbackScope
设置的作用域),this.target
) 或者边界坐标 (this.maxX
,this.minX
,this.maxY
,以及this.minY
). 默认情况下,pointerEvent
(与 Draggable 相关的最后的鼠标或触摸事件)将作为唯一的参数传递给回调函数,这样你可以例如访问它的pageX
,pageY
,target
,currentTarget
等属性。这不同于onDrag
的是它可以在每个 requestAnimationFrame 中触发多次。一般来说,最好使用onDrag
,但如果由于某些原因你需要在拖动事件上执行操作,也可以使用这个选项。.stopPropogation
或者.stopImmediatePropogation
在拖动事件上的操作。 - 函数- 当鼠标(或触摸)按下元素时应调用的一个函数。在这个函数中,
this
指向 Draggable 实例(除非你明确指定了使用callbackScope
设置的作用域),this.target
) 或者边界坐标 (this.maxX
,this.minX
,this.maxY
,以及this.minY
). 默认情况下,pointerEvent
(最后一个与 Draggable 相关的鼠标或触摸事件)将作为唯一参数传递给回调,这样您可以例如访问pageX
,pageY
,target
,currentTarget
,等等。 - 数组- 提供给
onPress
回调函数的可选参数数组。例如,onPressParams: ["drag started", 5]
可以与此代码一起使用:onPress: function(message, num) { console.log("message: " + message + ", num: " + num); }
. - 函数- 不论是否实际拖动了内容,在目标元素上按下的鼠标(或触摸)释放后立即调用该函数。在此函数内,
this
指向 Draggable 实例(除非你明确指定了使用callbackScope
设置的作用域),this.target
) 或者边界坐标 (this.maxX
,this.minX
,this.maxY
,以及this.minY
). 默认情况下,pointerEvent
(最后一个与 Draggable 相关的鼠标或触摸事件)将作为唯一参数传递给回调,这样您可以例如访问pageX
,pageY
,target
,currentTarget
,等等。 - 数组- 提供给
onRelease
回调函数的可选参数数组。例如,onReleaseParams: ["drag ended", 5]
可以与此代码一起使用:onRelease: function(message, num) { console.log("message: " + message + ", num: " + num); }
. - [元素 | 字符串 | 对象]- 如果你只想让某个特定区域(如窗口的顶部栏)触发拖动,而不是整个元素,你可以定义一个子元素作为触发器,比如
trigger: yourElement
,trigger: "#topBar"
,或者trigger: $("#yourID")
。你可以将触发器定义为一个元素或者选择器字符串。 - 字符串- 表示拖动类型(拖动应该影响的属性)。以下任意一个都可以使用:[
"x,y"
(基本上是 transform 的translateX
和translateY
属性) |"left,top"
|"rotation"
|"x"
|"y"
|"top"
|"left"
]。默认值是"x,y"
. - Boolean- 默认情况下,对于垂直或水平拖动,当一个元素被按下/触摸时,它的
zIndex
被设置为一个较高的值(默认值为1000
),并且每当新的元素被按下/触摸时,这个数值会递增并应用到新元素上,以确保堆叠顺序看起来正确(新按下的对象上升到最上层),如果你希望跳过此行为,则设置zIndexBoost: false
.
属性
描述
吸附
Draggable 拥有高级吸附功能。你可以定义snap
值来控制 Draggable 应该在config
对象中松开之后吸附,或者你可以定义一个liveSnap
值用于 Draggable 在拖动过程中吸附。可以通过以下任意一种方式定义这些值:
作为一组对齐到的预设值
Draggable.create("#id", {
type: "x,y",
liveSnap: {
//snaps to the closest point in the array, but only when it's within 15px (new in GSAP 1.20.0 release):
points: [
{ x: 0, y: 0 },
{ x: 100, y: 0 },
{ x: 200, y: 50 },
],
radius: 15,
},
});
points
是一个特殊属性,允许你将两种x
和y
逻辑结合到一个地方。你也可以使用单独的属性数组:
Draggable.create("#id", {
type: "x,y",
liveSnap: {
//x and y (or top and left) can each have their own array of values to snap to:
x: [0, 100, 200, 300],
y: [0, 50, 100, 150],
},
});
作为具有自定义逻辑的函数
Draggable.create("#id", {
type: "x,y",
liveSnap: {
points: function (point) {
//if it's within 100px, snap exactly to 500,250
var dx = point.x - 500;
var dy = point.y - 250;
if (Math.sqrt(dx * dx + dy * dy) < 100) {
return { x: 500, y: 250 };
}
return point; //otherwise don't change anything.
},
},
});
或者使用单独属性对应的函数:
Draggable.create("#id", {
type: "x,y",
liveSnap: {
x: function (value) {
//snap to the closest increment of 50.
return Math.round(value / 50) * 50;
},
y: function (value) {
//snap to the closest increment of 25.
return Math.round(value / 25) * 25;
},
},
});
对于旋转 Draggable 来说也同样简单:
Draggable.create("#id", {
type: "rotation",
liveSnap: {
rotation: function (value) {
//snap to the closest increment of 10.
return Math.round(value / 10) * 10;
},
},
});
获取速度值
只要你加载了 InertiaPlugin 并设置了inertia: true
在你的 Draggable 上,就可以使用InertiaPlugin.getVelocity()
方法。Draggable 将根据其使用的type
自动跟踪必要属性的速度(例如type: "x,y"
将跟踪x
和y
, type: "rotation"
将跟踪旋转等)。
//positional velocity
Draggable.create("#movableID", {
type: "x,y",
inertia: true,
onDragEnd: function () {
console.log(
"x velocity is: " +
InertiaPlugin.getVelocity(this.target, "x") +
" and the duration is " +
this.tween.duration() +
" seconds."
);
},
});
注释、依赖项和限制说明
-
在大多数情况下,应该使用
.pointerX
和.pointerY
而不是使用事件的位置信息(如.pageX
/.pageY
或类似方法),因为 GSAP 试图对所有浏览器中的位置信息进行标准化处理。 -
如果你希望某个特定元素是“可点击的”,从而被 Draggable 忽略,只需为其添加一个
data-clickable="true"
属性,或者onclick
。默认情况下,Draggable 会自动忽略<a>
,<input>
,<select>
,<button>
,以及<textarea>
元素的点击。如果你希望运行自己的逻辑判断对象是否应被视为“可点击”,可以将clickableTest
配置属性设为你选择的一个返回布尔值的函数。true
或者false
. -
Draggable 可以不依赖 InertiaPlugin 使用,但这样做将禁用任何基于动量的运动(例如快速滑动对象后让它继续减速移动)。这两个工具完美配合使用 🫶。
-
为了使元素能够通过它们的
top
和left
CSS 属性移动,你必须确保这些元素的position
CSS 属性设置为relative
或者absolute
(这是 CSS 的工作方式)。 -
默认情况下,所有的回调函数以及
snap
函数和liveSnap
函数都绑定到了关联的 Draggable 实例,所以this
指向 Draggable 实例。你可以使用this.x
和this.y
在这些函数中获取当前的水平或垂直值。如果设置了边界,还可以使用this.maxX
,this.minX
,this.maxY
,以及this.minY
. -
来获取该实例的合法最大和最小值。InertiaPlugin loaded! To use it, set
inertia: true
在vars
config 对象,例如Draggable.create(yourObject, {inertia: true});
. -
如果你使用了一个元素作为边界,它不应该与目标元素具有不同的旋转角度。
-
如果你混合使用时间轴和可拖动对象,你可能需要使用代理元素。更多信息请查看此演示.
属性
autoScroll: 数值 | 当 |
deltaX: 数值 | 自上次拖动事件以来与 x 相关值的变化。 |
deltaY: 数值 | 自上次拖动事件以来与 y 相关值的变化。 |
结束旋转: 数值 | [只读] [仅适用于 type:"rotation"] Draggable 实例的结束旋转角度,该值在拖动结束后鼠标/触摸释放时立即计算得出,这意味着你可以用它来精确预测之后松手时它将停在何处。 |
结束X坐标: 数值 | [只读] Draggable 实例的结束X(水平)位置,该值在拖动结束后鼠标/触摸释放时立即计算得出,这意味着你可以用它来精确预测之后松手时它将停在何处。 |
结束Y坐标: 数值 | [只读] Draggable 实例的结束Y(垂直)位置,该值在拖动结束后鼠标/触摸释放时立即计算得出,这意味着你可以用它来精确预测之后松手时它将停在何处。 |
isPressed:布尔值 | 如果 Draggable 正被按下,此值将是 |
是否正在抛掷:布尔值 | 报告 Draggable 的目标是否正使用 InertiaPlugin 补间动画进行抛掷。 |
lockAxis:布尔值 | 根据初始移动方向锁定为单轴运动。 |
锁定轴:字符串 | |
最大旋转角度: 数值 | 当设置了边界限制时, |
最大X坐标: 数值 | 当设置了边界限制时, |
最大Y坐标: 数值 | 当设置了边界限制时, |
最小旋转角度: 数值 | 当设置了边界限制时, |
最小X坐标: 数值 | 当设置了边界限制时, |
最小Y坐标: 数值 | 当设置了边界限制时, |
指针事件: 对象 | [只读] 影响当前 Draggable 实例的最新指针事件(可以是鼠标事件或触摸事件)。 |
指针X坐标: 数值 | [只读] 与 Draggable 最近一次事件相关联的指针(鼠标或触摸)的X(水平)位置(如 event.pageX)。 |
指针Y坐标: 数值 | [只读] 与 Draggable 最近一次事件相关联的指针(鼠标或触摸)的Y(垂直)位置(如 event.pageY)。 |
旋转角度: 数值 | [只读] [仅适用于 |
startX: 数值 | [只读] 最近一次拖动开始时 Draggable 实例的起始 |
startY: 数值 | [只读] 最近一次拖动开始时 Draggable 实例的起始 |
目标对象: 对象 | 正在被拖动的对象。 |
补间动画: 补间动画(Tween) | [只读] 当鼠标(或触摸)释放时创建的补间动画(Tween)实例(当 |
vars: 对象 | 这个 |
x: 数值 | [只读] Draggable 实例的当前位置(水平坐标)。 |
y: 数值 | [只读] Draggable 实例的当前位置(垂直坐标)。 |
zIndex: 数值 | [静态] 当元素被按下/触摸时,默认应用的起始 zIndex 值(用于定位类型,如 |
方法
添加事件监听器( ) ; | |
应用边界( bounds:Element | String | Object ) ; | 对 Draggable 应用新的边界限制。 |
创建 Draggable( target:Object, vars:Object ) : Array | [静态] 一种比构造函数更灵活的创建 Draggable 实例的方式(相比 |
disable( ) : Draggable | 禁用 Draggable 实例,使其无法再拖动(除非调用了 |
enable( ) : Draggable | 启用 Draggable 实例。 |
启用状态( value:Boolean ) : Boolean | 获取或设置启用状态。 |
结束拖动( event:Object ) : void | 可以通过调用 |
获取 Draggable( target:Object ) : Draggable | [静态] 提供了一种简便方式来获取与特定 DOM 元素关联的 Draggable 实例。 |
获取拖动方向( from:String | Element ) : String | 返回 |
碰撞检测( testObject:Object, threshold:[Number | String] ) : Boolean | 提供一种简便方法来测试目标元素是否根据指定阈值与另一特定元素(或鼠标位置)发生重叠。 |
kill( ) : Draggable | 禁用 Draggable 实例并从内部查找表中移除,以便使其有资格被垃圾回收,并且不能再拖动(除非调用了 |
开始拖动( event:Object, align:Boolean ) : void | 强制 Draggable 开始拖动。 |
自拖动以来的时间( ) : Number | 返回自上次拖动结束以来经过的时间(以秒为单位)。 |
更新( applyBounds:Boolean, sticky:Boolean ) : Draggable | 更新 Draggable 的 x/y 属性,以反映目标元素的当前位置。 |
示例演示
查看完整系列的使用演示和我们最喜欢的社区灵感演示在 CodePen 上。
Draggable 示例演示