Skip to main content

dom元素拖拽

2021-04-18|
JS HTML

  之前找实习的时候,面试官出了道 “原生 JS 实现 div 元素拖拽”,当时实现了个大概,不过很多细节都没写好,刚好最近又看到了相关文章,因此这里再好好整理一下 JS 中的元素拖拽实现。

原生 JS 实现 div 拖拽#

实现效果:

  要实现这样的元素拖拽效果,一般思路是这样的:

  1. 首先要被拖拽的 div 元素需要是定位元素,因为我们要使用 lefttop 样式来不断更新 div 的位置
  2. 设置一个 flag ,当鼠标左键在 div 元素上按下时,flag 设为 true,表示能够进行拖拽,且记录鼠标位置与 div 元素左上角的相对距离,用于后续 div 窗口的位置计算
  3. 当鼠标移动时,若 flagtrue,那么根据鼠标位置实时更新 div 的位置,且当 div 元素超出当前视口时,要进行判断处理使其保留在视口内。
  4. 当鼠标松开时,flag 重新设置为 false

  细节看代码:

<div class="container">    <div class="box"></div></div>

  在上面的代码中,我们使用了 dom.getBoundingClientRect() 来获得 div 元素的宽高和距内容页面左上角的距离,当然也可以使用 dom.offsetTopdom.offsetLeftdom.offsetHieghtdom.offsetWidth 来获取对应值计算。

  另外,注意到 JS 代码的最后三行,我们将 mousedown 事件绑定在了 div 元素上,而 mousemovemouseup 事件则绑定在了 document 对象上。

  mousedown 事件的绑定就不用说了,因为只有在鼠标点击 div 元素时,我们才能拖拽它;而 mousemove 事件绑定在 document 对象上的原因是为了在鼠标移出视口时,元素仍能进行拖拽(如鼠标移出了视口上方,当左右仍能进行移动),若 mousemove 绑定在了 div 元素上,那么鼠标移开视口时, div 元素就不动了,拖拽体验上就变差了;mouseup 也是同理,鼠标移开视口时松开鼠标的话需要正确的设置状态。

HTML 拖拽 API#

  在 HTML 中,默认只有图像、超链接和选择的文本可进行拖拽之外,其他的元素是不能进行拖拽的。

  不过 HTML 中也提供了一些 API 来支持设置其他元素的拖放效果。

  这边的拖拽与上面原生实现的拖拽不同,对于原生的拖拽 API,拖拽操作除了需要有一个可拖拽(draggable)元素外,还需要有一个可进行放置(droppable)的元素。在拖拽的过程中,能通过一系列的拖拽事件来对拖拽元素进行状态的监听,以便于自定义动作和数据的传输。

  一些拖拽事件如下:

事件On型事件处理程序触发时刻
dragondrag当拖拽元素或选中的文本时触发。
dragendondragend当拖拽操作结束时触发 (比如松开鼠标按键或敲“Esc”键). (见结束拖拽)
dragenterondragenter当拖拽元素或选中的文本到一个可释放目标时触发(见 指定释放目标)。
dragexitondragexit当元素变得不再是拖拽操作的选中目标时触发。
dragleaveondragleave当拖拽元素或选中的文本离开一个可释放目标时触发。
dragoverondragover当元素或选中的文本被拖到一个可释放目标上时触发(每100毫秒触发一次)。
dragstartondragstart当用户开始拖拽一个元素或选中的文本时触发(见开始拖拽操作)。
dropondrop当元素或选中的文本在可释放目标上被释放时触发(见执行释放)。

  在拖拽过程中,可以使用 DataTransfer, DataTransferItemDataTransferItemList 来传输与拖拽元素绑定的数据。

  因此实现一个 HTML 元素的拖拽,一般需要以下几个步骤:

  1. 给想要拖拽的元素设置 draggable 属性为 true
  2. 设置拖拽监听事件来完成自己的需求
  3. 若有需要,在监听事件中设置拖拽数据

  下面是一个简单的拖拽示例:可以将一个图片或是 div 元素拖入蓝框中,或是从本地文件中拖入图片,在拖动的过程中,框线的颜色会随拖动元素的状态而改变

代码如下:

<div className="html-drag-container">    <div id="html-drag-box-container">        <div class="html-drag-box" draggable="true"></div>    </div>    <div id="html-drag-img-container">        <img class="html-drag-img" src="https://gitee.com/yleave/imagehost1/raw/master/img/cat.png"></img>    </div>        <div class="html-drop-box"></div>
    <button id="reset-btn">reset</button></div>

REF#