起因

最近在公司打杂的时候,突然分到了一个锅,就是要支持一个新的功能:用户可以通过拖曳组件来改变组件的顺序。因此,这阵子就看了一下网上的一些drag和drog的文章以及W3C的介绍,然后自己亲手实践了一下,毕竟打码,才能变得更强。

首先,先放一个我的demo,大家可以去那里随便拖动一下玩一玩:

https://chenjigeng.github.io/example/drag.html

知识储备

与drag和drog有关的属性和事件

  • draggable属性: 如果你想让一个元素变得可以拖曳的话,那么你就必须设置它的draggable=true,如下
<div class='target' draggable="true"></div>

这样,该元素就可以拖动了

  • ondragstart: 当元素开始被拖动时,触发该事件,目标对象是被拖动的元素
  • ondragover: 当被拖动元素在悬挂元素上移动的时候,该事件触发。目标对象是被拖动元素悬挂的那个元素。
  • ondragleave: 当被拖动元素离开悬挂元素时,触发该事件。目标对象是被拖动元素悬挂的那个元素。
  • ondrop: 当鼠标松开被拖动元素的时候,触发该事件。目标对象是被拖动元素悬挂的那个元素。
  • ondragend: 当鼠标松开被拖动元素的时候,触发该事件。目标对象是被拖动的元素。其中,ondrop事件会先于ondragend事件触发。
  • event.preventDefault: 当触发ondragover事件的时候,必须使用event.preventDefault(),否则的话,ondrop事件就不会触发
  • event.dataTransfer.effectAllowed:设置或返回被拖动元素允许发生的拖动行为。可设置的属性很多,这里我们就不细说,感兴趣的可以去查下,一般来说,我们都设置为"move".

插入节点的方法

  • 将节点插入到另一个节点前面,代码如下
 function insertBefore(insertNode, node) {
node.parentNode.insertBefore(insertNode, node)
}

这个其实比较简单,就是找到节点的父亲,然后将要插入的节点放到节点的前面。

  • 将节点插入到另一个节点后面,代码如下图
 function insertAfter(insertNode, node) {
if (node.nextElementSibling) {
insertBefore(insertNode, node.nextElementSibling)
} else {
node.parentNode.appendChild(insertNode)
}
}

这个其实也挺简单的,就是如果该节点有兄弟节点的话,那么就将插入节点放到它兄弟节点的前面,否则,则说明该节点是父节点的最后一个节点,因此直接将插入节点放到父节点的末尾。

实践

在这里,我们要做的就是一个支持各个图片拖曳来交换位置的玩意,不过,当图片交换位置的时候,不单单是图片交换位置,而是包含图片的容器交换位置。

1.我们先放置几张图片,并且将它们的dragable设置为true,这样它们就可以拖动了。代码如下:

<body>
<div class='target' draggable="true">
<img src="./imgs/1.jpeg" alt="1">
</div>
<div class='target' draggable="true">
<img src='./imgs/2.jpg' />
</div>
<div class='target' draggable="true">
<img src="./imgs/3.jpg" alt="ss">
</div>
<div class='target' draggable="true">
<img src="./imgs/4.jpg" alt="ss">
</div>
</body>

效果:



2.为每个div都设置一个ondragstart函数,当该函数触发的时候,进行初始化操作,比如记录当前的目标对象,拖动目标的y值,以及设置拖动的效果。

// 拖动的目标对象
let target = ''
// 拖动的目标对象的y值
let targetOffsetTop = 0
// 当元素开始被拖动时,触发该事件,目标对象是被拖动的元素
function handleDragStart(ev) {
target = findTarget(ev.target)
targetOffsetTop = ev.target.offsetTop
ev.dataTransfer.effectAllowed = 'move'
}
// 找到类名为target的目标对象
function findTarget(node) {
if (!node || node == document) {
return null
}
if (node.classList.contains('target')) {
return node;
}
return findTarget(node.parentNode)
}

3.为每个div注册一个ondragover事件和ondragleave事件,在ondragover事件里,主要是调用event.preventDefault来防止ondrog不会被触发,并且为了看起来更明显,当ondragover事件触发的时候,为目标对象增加一个dotted类。当ondragleave事件触发的时候,则把dotted类从目标对象移除。

// 当被拖动元素在悬挂元素上移动的时候,该事件触发。目标对象是被拖动元素悬挂的那个元素。
// 必须执行event.preventDefault(),不然的话ondrop不会触发
function handleDragOver(ev) {
ev.preventDefault();
ev.target.classList.add('dotted')
}
// 当被拖动元素离开悬挂元素时,触发该事件。目标对象是被拖动元素悬挂的那个元素。
function handleDragLeave(ev) {
ev.target.classList.remove('dotted')
}

4.为每个div注册ondrog事件和ondragend事件,ondrog事件是重点,它主要是根据被拖动元素和被拖动元素悬挂的那个元素的坐标,来决定是要将被拖动元素插入到悬挂元素的前面还是后面。而ondragend主要是用于将target设置为null,代码如下:

// 当鼠标松开被拖动元素的时候,触发该事件。目标对象是被拖动元素悬挂的那个元素。
function handleDrog(ev) {
let resultOffsetTop = ev.target.offsetTop
if (targetOffsetTop < resultOffsetTop) {
insertAfter(target, findTarget(ev.target))
}
else {
insertBefore(target, findTarget(ev.target))
}
ev.target.classList.remove('dotted')
}
// 将节点插入到另一个节点前面
function insertBefore(insertNode, node) {
node.parentNode.insertBefore(insertNode, node)
}
// 将节点插入到另一个节点后面
function insertAfter(insertNode, node) {
if (node.nextElementSibling) {
insertBefore(insertNode, node.nextElementSibling)
} else {
node.parentNode.appendChild(insertNode)
}
}
// 当松开鼠标的时候,触发该事件。目标对象是被拖动的对象
function handleDragEnd(ev) {
target = null
}

这样子,我们就实现了一个可以通过拖曳来改变图片顺序的一个小玩意啦~完整的代码放到https://github.com/chenjigeng/something 上了~有兴趣的可以git clone下来跑一跑

本文地址在->本人博客地址, 欢迎给个 start 或 follow

HTML5 drag和drop的亲手实践的更多相关文章

  1. html5 drag and drop

    注:链接.图片默认是draggable的. mousemove在整个拖放的过程中不会被触发. dragStart设置: e.dataTransfer.effectAllowed = "mov ...

  2. 20 Best Drag and Drop jQuery Plugins--reference

    reference from:http://dizyne.net/20-best-drag-drop-jquery-plugins/ jQuery has done a great job repla ...

  3. angularjs drag and drop

    angular-dragula Drag and drop so simple it hurts 480 live demo angular-drag-and-drop-lists Angular d ...

  4. 使用 Drag and Drop 给Web应用提升交互体验

    什么是 Drag and Drop (拖放)? 简单来说,HTML5 提供了 Drag and Drop API,允许用户用鼠标选中一个可拖动元素,移动鼠标拖放到一个可放置到元素的过程. 我相信每个人 ...

  5. HTML5 之拖放(drag与drop)

    拖放(Drag 和 drop)是 HTML5 标准的组成部分. 拖放是一种常见的特性,即抓取对象以后拖到另一个位置. 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放. HTML5 拖放实例 ...

  6. 通过HTML5的Drag and Drop生成拓扑图片Base64信息

    HTML5 原生的 Drag and Drop是很不错的功能,网上使用例子较多如 http://html5demos.com/drag ,但这些例子大部分没实际用途,本文将搞个有点使用价值的例子,通过 ...

  7. 基于HTML5的Drag and Drop生成图片Base64信息

    HTML5的Drag and Drop是很不错的功能,网上使用例子较多如 http://html5demos.com/drag ,但这些例子大部分没实际用途,本文将搞个有点使用价值的例子,通过Drag ...

  8. [转]人人网首页拖拽上传详解(HTML5 Drag&Drop、FileReader API、formdata)

    人人网首页拖拽上传详解(HTML5 Drag&Drop.FileReader API.formdata) 2011年12月11日 | 彬Go 上一篇:给力的 Google HTML5 训练营( ...

  9. HTML5 拖放(Drag 和 Drop)功能开发——基础实战

    随着HTML5的普及度越来越高,现在写代码也遇到一些了,经过同事的点播开展了一次Dojo活动用以技术交流,我也乘此机会将HTML5的拖放功能整理了一下. 简介 拖拽(Drag/Drop)是个非常普遍的 ...

随机推荐

  1. 在vue-cli搭建的项目中增加后台mock接口

    用vue-cli搭建一个前端开发环境确实是极其方便,在写前端代码肯定也是少不了需要调用后台提供的业务接口进行前后端交互,特别在敏捷开发中,前后端都要提前确定业务接口并进行打桩,在开发过程中基本是没有现 ...

  2. Windows下以Local模式调试SparkStreaming的WordCount例子

    1.下载Windows版的NetCat https://eternallybored.org/misc/netcat/ 2.启动NetCat nc -l -p 9999 3.将SAPRK_HOME\c ...

  3. 全景智慧掌上城,飞入寻常百姓家——VR全景智慧城市

    随着腾讯和阿里陆续将AR技术加入到新年抢红包大战之中,人们对于VR.AR未来的应用空间又多了一些想象.同传统的基于二维元素的抢红包不同,借助VR.AR的技术能够让用户获得一种更加真切的体验,这种体验相 ...

  4. intersect for multiple vectors in R

    Say you have a <- c(1,3,5,7,9) b <- c(3,6,8,9,10) c <- c(2,3,4,5,7,9) A straightforward way ...

  5. python 列表转字典

    def func_data(text): data = dict() for kv in text.split(','): k_v = kv.split(':') data[k_v[0]] = k_v ...

  6. 第40篇 使用Sublime+MarkDown快速写博客

    原文地址:http://blog.laofu.online/2017/06/03/how-use-sublime/ 前端的开发人员应该都知道sublime的神器,今天就说说如何使用sublime结合m ...

  7. Java IO流之转换流

    一.转换流 1.在IO包中,实际上就是分为字节流和字符流,但是除了这两个流之外,还存在了一组字节流-字符流的转换流 2.转换流用于在字节流和字符流之间转换 3.转换流本身是字符流 二.两种转换流 Ou ...

  8. javaCV开发详解之技术杂烩:javaCV能帮我们做什么?能实现什么功能?ffmpeg和openCV能实现功能,javaCV如何做到更快、更简单的实现相应的功能?等等一堆实用话题

    前言: 该篇文章旨在帮助刚接触javaCV的盆友系统的认识音视频.javaCV.图像处理相关的体系知识和一些实用的知识. 序: javaCV早期因为内置了openCV库,所以常用来做图像识别应用,现在 ...

  9. linux定时任务访问url

    这次linux定时任务设置成功,也算是自己学习linux中一个小小的里程碑.:) 撒花撒花--- 以下操作均是在ubuntu 下操作的,亲测有效,其他的linux系统还望亲们自己去查.鞠躬感谢! 1 ...

  10. js变量提升和函数提升

    变量,作为编程语言最基础的部分,每种语言的变量不尽相同,但又大径相庭.大部分编程语言的变量有块级作用域,如if.for.while... 但JavaScript不纯在块级作用域,而是函数作用域,并且有 ...