基本介绍 📝

  • 在 web 页面中,如果需要改变多个元素的位置,可以通过元素拖动来实现。HTML5中加入了一个全局属性draggable,通过设置该属性的值为 true/false 来控制元素是否可拖动。需要注意的是:
  • 链接和图片默认是可拖动的,可以通过将 draggable 设置为false将他们变为不可拖动元素。
  • Internet Explorer 8 及更早 IE 版本不支持 draggable 属性。
  • 本文图片拖拽排序的实现主要利用了元素在拖放的过程中会触发的 ondragstartondragend 和 ondragover 事件,具体触发时机和其他事件可以参考 MDN,碍于篇幅,本文将不再进行阐述。

效果演示 🤩

  • 先看效果:

HTML5 拍照界面 html5图片排列_html5多个图片位置

  • 下面将介绍思路和具体的实现代码。

思路分析 🤔

  • 本文图片拖拽排序的实现主要利用了元素在拖放的过程中会触发的 ondragstartondragend 和 ondragover 事件。
  • 通过监听 ondragstart 事件,将当前被拖动元素的数据保存下来,并给其增加特殊样式(设置元素的透明度和放大元素)。
  • 通过监听 ondragend 事件,将上面一步设置在被拖动元素的特殊样式删除。为了减少内存消耗,我们把被拖动元素的 ondragend 事件委托到最外层容器(事件委托)
  • 实现最重要的拖动排序功能,主要是为元素绑定 ondragover 事件。当 ondragover 事件被触发时,需要获取当前鼠标的位置(event.clientXevent.clientY),计算出当前鼠标拖动到哪个元素上通过判断当前被拖动元素和其他元素的位置,从而实现元素的交换排序。
  • 下面小节将介绍具体的实现代码。

具体实现 🧐

基本布局

  • 在实现拖拽功能之前,先完成基本布局:
/** index.tsx */



);


};

export default React.memo(DragAndDropPage); 复制代码

  • 样式文件的内容如下:
/** index.module.scss */
.wrapper {
  overflow: hidden;
  margin: 100px auto;
  padding: 10px 0;
  background: #fff;
  border-radius: 5px;
}

.list {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 0;

  position: relative;
}

.item {
  position: absolute;
  display: flex;
  align-items: center;
  transition: all 0.2s ease-in-out;
}
复制代码

效果如下: 

HTML5 拍照界面 html5图片排列_拖拽_02

  • 通过上述代码可以看到,尽管展示的 li 元素看起来像是按照 list 原始顺序展示,但是实际上其渲染顺序是由排序后的列表 sortedList 决定的。

HTML5 拍照界面 html5图片排列_事件委托_03

之所以表现像是按照 list 原始顺序展示,是通过在 sortedList.map 时根据当前 item 在 list 数组的索引 index 计算出其CSS的left和 top 属性 

HTML5 拍照界面 html5图片排列_数据保存_04

拖拽实现

拖动增加特殊样式
  • 首先,为最外层的容器 wrapper 绑定 ref 属性,方便在之后的事件方法中获取到该 DOM 节点,并将每个 li 元素的 draggable 属性的值设置为 true/false 使其变为可拖动元素,同时绑定 ondragstart 事件:

HTML5 拍照界面 html5图片排列_html5多个图片位置_05

  • handleDragStart 方法主要是将当前被拖动元素的数据保存下来,并给其增加特殊样式(设置元素的透明度和放大元素),相关代码如下:

HTML5 拍照界面 html5图片排列_拖拽_06

  • 此时效果如下:

HTML5 拍照界面 html5图片排列_事件委托_07

拖放结束移除特殊样式
  • 可以看到,当开始拖动元素时,元素应用了特殊样式,但是松开鼠标后元素没恢复原来的样式。这时候就需要在拖动结束后删除前面添加的特殊样式。
  • 为了减少内存消耗,我们把被拖动元素的 ondragend 事件委托到最外层容器(事件委托),相关代码如下:

HTML5 拍照界面 html5图片排列_数据保存_08

  • 此时效果如下:

HTML5 拍照界面 html5图片排列_HTML5 拍照界面_09

拖动排序
  • 接下来将实现最重要的拖动排序功能,主要是为元素绑定 ondragover 事件。
  • 默认情况下,数据/元素不能放置到其他元素中。如果要实现该功能,我们需要防止元素的默认处理方法。我们可以通过调用 event.preventDefault() 方法来实现 ondragover 事件。
  • 当 ondragover 事件被触发时,需要获取当前鼠标的位置(event.clientXevent.clientY),计算出当前鼠标拖动到哪个元素上通过判断当前被拖动元素和其他元素的位置,实现元素的交换排序,关键的是实现 updateList 方法,相关代码如下:
/** 将某元素插入到数组中的某位置 */



);


};

export default React.memo(DragAndDropPage); 复制代码

  • 效果如下:

HTML5 拍照界面 html5图片排列_html5多个图片位置

完整代码
  • index.tsx文件中的内容:

HTML5 拍照界面 html5图片排列_拖拽_11

  • 样式文件内容:

HTML5 拍照界面 html5图片排列_数据保存_12

总结 👀

  • 本文介绍了如何在 React 项目中实现简易的图片拖动排序。主要是通过给需要拖动的元素设置 draggable 属性,并监听相关的事件,进行样式增减、拖动排序等。

以上内容如有遗漏错误,欢迎留言 ✍️指出,一起进步💪💪💪

如果觉得本文对你有帮助,🏀🏀留下你宝贵的 👍