我们如何使用DOM事件
这个页面详细介绍了我们如何使用DOM输入事件,我们对它们做了什么,以及如何在我们的使用之上构建工作。通常,您不需要知道此信息但是,如果您还将自己的事件处理程序绑定到 window 或 一个拖动控制,这些信息会有用。
⚠️注意:由于webkit中的一个错误,特别是当
event.preventDefault()被调用,诸如类mousemove事件将无法正确设event.defaultPrevented为true。您可以关注此问题的进展在这里.
知识预备
本页假定您具有DOM事件的工作知识。有关DOM事件的详细介绍,请参阅:
安全事件绑定
无需深入了解下面的所有细节,这里是react-beautiful-dnd最上层的最高安全的事件处理程序:
这些都可以添加到拖动控制,’树’上任何其他地方或直接在window.
onClick:如果作为拖动交互部分发生了,event.defaultPrevented属性将设置为true。即使拖动未完成诸如mouseup或touchend之类的预先单击操作。看马虎点击和点击预防.onKeyDown:如果它被用作拖拽的一部分,event.defaultPrevented属性将设置为true。如果你想添加onKeyDown到拖动控制,你将需要猴子补丁 下DragHandlePropsonKeyDown事件处理程序
您可能需要使用来自onDragStart和onDragEnd的信息来提高事件处理程序的逻辑了解,明确知道在这些事件发生时,是否为一个拖动了.
欢迎您添加其他事件处理程序,但您可能更需要onDragStart和onDragEnd的信息.
通用规则
事件预防
当我们使用输入事件作为拖放交互的一部分时,我们通常会调用event.preventDefault()函数,此函数会退出标准浏览器的事件行为。当调用event.preventDefault(),也不会停止我们事件的传播,所有即使我们使用一个mousemove拖动事件,我们也不会阻止该事件发布(传播),最后被您的事件处理程序接收.
- 我们用:
event.preventDefault() - 我们不使用:
event.stopPropagation()
我们添加了一些事件处理程序到拖动控制本身(见DragHandleProps)和我们又添加了其他的到window在里面捕获阶段。这意味着只要您在冒泡阶段中使用事件处理程序(这是事件处理程序的默认设置),然后事件的行为将如此页面所述.
为了知道我们是否已经把事件用在了拖放功能,您需要检查event.defaultPrevented属性.
所以假设你要添加一个window的click处理程序。你可以这样做:
window.addEventListener('click', (event: MouseEvent) => {// 事件 已用于 drag 和 dropif (event.defaultPrevented) {return;}doMyCoolThing();});
直接和间接的行动
某些用户事件会对拖动有直接影响:例如当鼠标拖动时的一个mousemove或用键盘向上箭头 ↑拖动时的keydown事件。这些直接事件都会有event.preventDefault()的调用,以此来阻止他们的默认浏览器行为。有些事件则会间接影响了,如当取消拖动时的resize事件之类。对于间接影响拖动的事件,并不会调用event.preventDefault()。影响拖拽的间接事件通常以取消拖动为主,例如reize或orientationchange事件.
鼠标拖动🐭
初始mousedown
preventDefault()会 被调用😞
这是我们规则集合中的唯一已知的例外。不幸的是,这只是第一个!
当用户第一次在拖动控制上触及mousedown时,我们不确定他们是否打算点击或拖动。理想情况下,我们不会调用preventDefault(),因为我们不确定它是否是拖动的一部分.但是,我们需要调用preventDefault(),这样是为了避免项目获得焦点,因为它有一个tabIndex.
我们还不确定是否会开始拖动
preventDefault()没有被调用
在我们将运动视为拖动之前,用户需要移动一个小阈值。在这段时间我们不会在任何mousemove事件调用preventDefault(),因为我们不确定他们是拖动还是,只是马虎点击
用户表示他们不是鼠标拖动
preventDefault()没有调用,因有让拖动结束的事件(例如mouseup和keydown)。在有挂起拖动时,任何keydown事件被激活将被视为间接取消拖动preventDefault()并不调用在随后的click事件,如果有的话
鼠标拖动已经开始,用户现在正在拖动
preventDefault()在mousemove事件中被调用preventDefault()在少数keydown事件中被调用,阻止其标准浏览器行为的事件preventDefault()在keyup事件中没有被调用,即使keydown被阻止了
拖动正在结束
preventDefault()在一个mouseup中被调用,如果它结束了拖动preventDefault()在退出 esckeydown中被调用,如果因为它直接结束拖动preventDefault()在下一个click事件时被调用,不管拖动是如何结束,都会发生事件.看马虎点击和点击预防preventDefault()不会在其他事件上调用,如resize间接结束了拖动preventDefault()在keyup事件不会被调用,即使它们导致拖动结束
触摸拖动📱
触摸拖动的逻辑与鼠标拖动的工作方式类似
初始touchstart
preventDefault()在touchstart没有被调用.
当用户在Draggable上按下他们的手指(或其他输入)时,我们不确定他们是否打算去单点,重压,滚屏要么拖动。因为我们不知道用户想要做什么, 反正我们不调用preventDefault()在这个事件上.
用户表示他们没有触摸拖动
preventDefault()不会在任何事件上被调用
用户可以通过将手指👇在元素组件上保持一小段时间🕑(长按)来开始拖动.如果用户在这段时间内,移动了,触发touchmove事件,那我们在这个事件上不调用preventDefault().
可通过如一个orientationchange或者一个touchcancel之类的时间取消触摸拖动。在这些事件上我们都不会调用preventDefault.
触摸拖动已开始,用户现在正在拖动
preventDefault()在touchmove事件上被调用
✌️
触摸拖动正在结束
preventDefault()在touchend事件上被调用preventDefault()在touchcancel事件上被调用preventDefault()在作为直接取消的退出 esckeydown上调用。preventDefault()在任何其他keydown事件不调用,因为哪些事件是间接取消.preventDefault()不会在其他如orientationchange事件上调用,因其可取消拖动
大力按压
- 如果拖动尚未开始,
preventDefault()没有被调用touchforcechange - 如果拖动已经开始但尚未发生移动,
preventDefault()没有被调用touchforcechange。重压会取消拖动且是间接取消. - 在拖动的
touchforcechange已经开始和touchmove已经结束了之后,preventDefault()调用。这是为了防范touchmove之后touchforcechange不应该发生.
键盘拖动🎹
我们只用
keydown事件应对用于键盘拖动,所以keyup事件中从来没有调用过preventDefault()
拖动开始
preventDefault()在keydown被调用
与鼠标拖动不同,键盘拖动会在用户按下空格键 空间时,立即开始。这个初始的键盘交互就会有event.preventDefault()调用.
拖着
- 如果事件被用作拖动的一部分(例如向上箭头 ↑),
preventDefault()在keydown被调用 - 当我们想要阻止标准浏览器行为(例如
enter键入),preventDefault()在keydown事件被调用 - 若我们不用于拖动的事件,
preventDefault()在keydown上没有被调用,
拖动结束
- 如果是空格键 space键的话,
preventDefault()在keydown被调用,因为它正在放下 - 如果是退出 esc键的话,
preventDefault()在keydown被调用,因为它明确取消拖动 preventDefault()不会在间接取消拖动的事件上调用,例如resize要么mousedown.
