Vue3中列表拖拽排序的实现示例
脚本之家 / 编程助手:解决程序员“几乎”所有问题!
脚本之家官方知识库 → 点击立即使用
本文主要内容分三个部分。先写了在 Vue3 中利用 HTML5
的 draggable
属性手写实现列表拖拽排序的功能。接下来记录了在 Element Plus
组件库中结合 sortable.js
使用,对表格组件 el-table
进行拖拽排序的。最后一个部分是 vuedraggable
拖拽组件的使用。
本文基于
Vite
、Vue3
、Element Plus
技术栈
draggable 实现拖拽排序
属性和事件
draggable
属性是 HTML5 新增的可拖拽属性。
在 HTML 中,除了图像、链接和选择的文本默认可拖拽外,其他元素默认是不可拖拽的。如果想让其他元素变成可拖拽的,首先需要把 draggable
属性设置为 true
。
设置完成之后,还需要结合一些事件才能完成拖拽:
拖拽元素的事件事件
- 拖拽元素的事件
事件 | 触发时机 |
---|---|
dragstart | 开始拖拽时执行 1 次 |
drag | 拖拽开始后多次触发 |
dragend | 拖动结束后触发 1 次 |
- 可释放目标的事件
事件 | 触发时机 |
---|---|
dragenter | 拖拽元素进入可释放目标时执行 1 次 |
dragover | 拖拽元素进入可释放目标时触发多次(100毫秒触发一次) |
drop | 拖拽元素进入可释放目标内释放时(设置了dragover此事件才会生效) |
可放置目标
dragenter
或 dragover
事件可用于表示有效的放置目标,也就是被拖拽元素可能放置的地方。
设置允许被被放置还需要阻止 dragenter
和 dragover
事件的默认处理。
做一个例子来理解 可放置目标
:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <div id= "div" ondragover= "dragover(event)" ondragenter= "dragenter(event)" " > 我是可放置目标 </div> <p id=" drag " draggable=" true " ondragstart=" dragstart(event) " ondragend=" dragend(event)" > 我是拖拽元素,把我拖拽到上面去 </p> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | let targetDom function dragstart(e) { } function dragenter(e) { e.preventDefault() targetDom = e.target } function dragover(e) { e.preventDefault() e.dataTransfer.dropEffect = 'move' } function dragend(e) { e.preventDefault() targetDom.appendChild(e.target) } |
DataTransfer 对象
DataTransfer
对象用于保存拖拽过程中的数据、设置拖动类型等。在所有拖动事件 event
的 dataTransfer
属性上都能获取到 DataTransfer
对象。
dataTransfer.dropEffect
设置拖拽的操作类型。值必须是none
, copy
, link
或 move
。
传递数据 (不建议使用这种方法,可能有兼容问题)只能在drop
事件中接收(测试的时候在其他拖拽事件中获取不到)
1 2 3 4 5 6 7 8 9 10 | function dragstart(e, index) { e.stopPropagation() e.dataTransfer.dropEffect = 'move' // 传数据 e.dataTransfer.setData( 'text/plain' , '111111111' ) } function drop(e) { // 接收数据 console.log(e.dataTransfer.getData( 'text/plain' )); } |
Vue3 中拖拽排序
根据上面描述的属性和事件在 Vue3 编写一个拖拽排序的列表大概分下面几个步骤:
- 创建一个列表,遍历渲染到页面
- 列表项添加
draggable="true"
- 列表项添加事件
dragstart
dragenter
dragend
dragover
- 在
dragenter
事件中,需要传入列表项的下标,实时进行元素的排序。排序的核心逻辑也是在dragenter
中 - 代码执行的逻辑是:列表项拖拽到可放置目标时,将该拖拽的元素从原位置删除,再将拖拽的元素插入到当前可放置目标的位置
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | <template> <div> <div class= "item" v- for = "(item, i) in drag.list" :key= "item.id" draggable= "true" @dragstart= "dragstart($event, i)" @dragenter= "dragenter($event, i)" @dragend= "dragend" @dragover= "dragover" > {{ item.name }} </div> </div> </template> <script setup> import { reactive } from 'vue' const drag = reactive({ list: [ { name: 'a' , id: 1 }, { name: 'b' , id: 2 }, { name: 'c' , id: 3 }, { name: 'd' , id: 4 }, { name: 'e' , id: 5 }, ] }) let dragIndex = 0 function dragstart(e, index) { e.stopPropagation() dragIndex = index setTimeout(() => { e.target.classList.add( 'moveing' ) },0) } function dragenter(e, index) { e.preventDefault() // 拖拽到原位置时不触发 if (dragIndex !== index) { const source = drag.list[dragIndex]; drag.list.splice(dragIndex, 1); drag.list.splice(index, 0, source); // 更新节点位置 dragIndex = index } } function dragover(e) { e.preventDefault() e.dataTransfer.dropEffect = 'move' } function dragend(e) { e.target.classList.remove( 'moveing' ) } </script> <style lang= "scss" scoped> .item { width: 200px; height: 40px; line-height: 40px; // background-color: #f5f6f8; background-color: skyblue; text-align: center; margin: 10px; color: #fff; font-size: 18px; } .container { position: relative; padding: 0; } .moveing { opacity: 0; } </style> |
此时是这样的效果:
这样就在 Vue3 中实现了拖拽排序。还可以利用 Vue 的<TransitionGroup>
内置组件,添加动画效果,让元素的过渡不会很生硬。
添加代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <template> <div> <TransitionGroup name= "list" tag= "div" class= "container" > <div class= "item" v- for = "(item, i) in drag.list" :key= "item.id" draggable= "true" @dragstart= "dragstart($event, i)" @dragenter= "dragenter($event, i)" @dragend= "dragend" @dragover= "dragover" > {{ item.name }} </div> </TransitionGroup> </div> </template> <style lang= "scss" scoped> .list-move, /* 对移动中的元素应用的过渡 */ .list-enter-active, .list-leave-active { transition: all 0.2s ease; } </style> |
效果如下:
sortable.js
接下来在 Element Plus
组件库中使用 sortable.js
进行表格排序。
Element Plus 是基于 Vue3 的常用的开源组件库
安装 sortable.js
使用 el-table
组件,写一个表格:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <template> <div> <el-table :data= "tableData" id= "dragTable" border style= "width: 800px;" > <el-table-column prop= "date" label= "Date" width= "180" /> <el-table-column prop= "name" label= "Name" width= "180" /> <el-table-column prop= "address" label= "Address" /> </el-table> </div> </template> <script setup> const tableData = [ { date: '2016-05-03' , name: 'Tom' , address: 'No. 189, Grove St, Los Angeles' , }, { date: '2016-05-02' , name: 'Cilly' , address: 'No. 189, Grove St, Los Angeles' , }, { date: '2016-05-04' , name: 'Linda' , address: 'No. 189, Grove St, Los Angeles' , }, { date: '2016-05-01' , name: 'John' , address: 'No. 189, Grove St, Los Angeles' , }, ] </script> |
现在就有了一个表格:
然后导入 sortable.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <script setup> import Sortable from 'sortablejs' import { onMounted } from 'vue' function setSort() { const el = document.querySelector( '#dragTable table tbody' ) new Sortable(el, { sort: true , ghostClass: 'sortable-ghost' , onEnd: (e) => { const targetRow = tableData.splice(e.oldIndex, 1)[0] tableData.splice(e.newIndex, 0, targetRow) console.log(tableData) }, }) } onMounted(() => { setSort() }) const tableData = [ // ... ] </script> |
在 onMounted
中,也就是组件挂载完成之后,实例化 Sortable()
,传入要进行拖拽排序的节点 el
和其它一些配置参数。现在可以进行拖拽了。
有些时候,可能需要按住拖动图标才可以进行拖动,需要添加 handle
配置,并指定对应的样式名。
1 2 3 4 5 6 7 8 9 10 11 12 | <el-table :data= "tableData" id= "dragTable" border style= "width: 600px; margin: 20px" > <!-- ...... 省略代码 --> <el-table-column label= "操作" width= "100" > <template #default> <div class= "handle-drag" > <el-icon> <Sort /> </el-icon> </div> </template> </el-table-column> </el-table> |
上面代码将表格添加了一个操作列,并将操作列的图标设置一个样式类。下面的配置表示只有包含.handle-drag
样式的元素才可以被拖动。其他位置不能被拖动。
vuedraggable
vue.draggable.next
是 Vue3 的拖拽组件,是基于 Sortable.js 实现的。可以用于拖拽列表、菜单、工作台、选项卡等常见的场景。
安装:
使用:
1 2 3 4 5 6 7 8 9 10 11 12 | <script setup> import draggable from 'vuedraggable' import { reactive } from 'vue' const state = reactive({ list1: [1, 2, 3, 4], list2: [ 'a' , 'b' , 'c' , 'd' ], }) function onStart() {} function onEnd() { console.log(state) } </script> |
先导入 draggable
并定义一些基础数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <template> <div style= "margin-left: 30px;" > <draggable :list= "state.list1" :force-fallback= "true" chosen-class= "chosen" animation= "300" @start= "onStart" @end= "onEnd" > <template #item="{ element }"> <div class= "item" > {{ element }} </div> </template> </draggable> </div> </template> |
其中 @start
和 @end
为拖拽开始和结束时的事件。chosen-class
为拖拽时的样式。
为组件设置相同的 group
属性,可以实现在不同的块之间拖拽。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <draggable group= "group" :list= "state.list1" > <template #item="{ element }"> <div class= "item bck1" > {{ element }} </div> </template> </draggable> <draggable group= "group" :list= "state.list2" > <template #item="{ element }"> <div class= "item bck2" > {{ element }} </div> </template> </draggable> |
相关地址
到此这篇关于Vue3中列表拖拽排序的实现示例的文章就介绍到这了,更多相关Vue3 列表拖拽排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
vue 绑定使用 touchstart touchmove touchend解析
这篇文章主要介绍了vue 绑定使用 touchstart touchmove touchend解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-03-03Vue路由钩子之afterEach beforeEach的区别详解
这篇文章主要介绍了Vue路由钩子 afterEach beforeEach区别 ,vue-router作为vue里面最基础的服务,学习一段时间,对遇到的需求进行一些总结。需要的朋友可以参考下2018-07-07解决vue的touchStart事件及click事件冲突问题
这篇文章主要介绍了解决vue的touchStart事件及click事件冲突问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-07-07
最新评论