html5多个图片位置_React 实现简易的图片拖动排序

8504cce38f202973064bc834a0302421.gif

基本介绍 📝

  • 在 web 页面中,如果需要改变多个元素的位置,可以通过元素拖动来实现。HTML5中加入了一个全局属性draggable,通过设置该属性的值为 true/false 来控制元素是否可拖动。需要注意的是:

    • 链接和图片默认是可拖动的,可以通过将 draggable 设置为false将他们变为不可拖动元素。

    • Internet Explorer 8 及更早 IE 版本不支持 draggable 属性。

  • 本文图片拖拽排序的实现主要利用了元素在拖放的过程中会触发的 ondragstartondragend 和 ondragover 事件,具体触发时机和其他事件可以参考 MDN,碍于篇幅,本文将不再进行阐述。

效果演示 🤩

  • 先看效果:

57681e98a48b3d7e6ce782cb09c62d76.gif

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

思路分析 🤔

  • 本文图片拖拽排序的实现主要利用了元素在拖放的过程中会触发的 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;
}
复制代码

效果如下: 758ed0b39ac3d3c4b7a1c8f9d9b0664e.gif

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

54cd20a3b963b054d19cd7237b31b494.png

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

拖拽实现

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

468c604d52eff8c59cf001f54b5d1884.png

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

dceb1a07eae902d4e3a2d87b928efb27.png

  • 此时效果如下:

ddab2122ec12cc5a767b8cf8db4ca4ef.gif

拖放结束移除特殊样式
  • 可以看到,当开始拖动元素时,元素应用了特殊样式,但是松开鼠标后元素没恢复原来的样式。这时候就需要在拖动结束后删除前面添加的特殊样式。

  • 为了减少内存消耗,我们把被拖动元素的 ondragend 事件委托到最外层容器(事件委托),相关代码如下:

3956e8972182e379636c762ef45841ec.png

  • 此时效果如下:

8c5d9f920ab801e5aba5b9440604e293.gif

拖动排序
  • 接下来将实现最重要的拖动排序功能,主要是为元素绑定 ondragover 事件。

  • 默认情况下,数据/元素不能放置到其他元素中。如果要实现该功能,我们需要防止元素的默认处理方法。我们可以通过调用 event.preventDefault() 方法来实现 ondragover 事件。

  • 当 ondragover 事件被触发时,需要获取当前鼠标的位置(event.clientXevent.clientY),计算出当前鼠标拖动到哪个元素上通过判断当前被拖动元素和其他元素的位置,实现元素的交换排序,关键的是实现 updateList 方法,相关代码如下:

/** 将某元素插入到数组中的某位置 */

);
}; export default React.memo(DragAndDropPage); 复制代码
  • 效果如下:

57681e98a48b3d7e6ce782cb09c62d76.gif

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

357417cbbdf3255c628e5d1845f596cc.png

  • 样式文件内容:

5f617c333c557c06cbc7a4c469b68576.png

总结 👀

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

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

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

参考资料

  1. React hook

  2. HTML 拖放 API

  3. 用两种不同的姿势来实现拖动排序

95922a50309e1bdf4534782588ba6ec4.gif

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值