El contenido principal de este trabajo se divide en tres partes. Primero, escribí la función de arrastrar y ordenar la lista a mano en Vue3 usando HTML5
el atributo. draggable
A continuación, registra cómo arrastrar y ordenar los componentes de la tabla en combinación con Element Plus
la biblioteca de componentes . La última parte es el uso de componentes de arrastrar y soltar.sortable.js
el-table
vuedraggable
Este artículo está basado en su pila de tecnología
Vite
.Vue3
Element Plus
implementos arrastrables clasificación de arrastrar y soltar
propiedades y eventos
draggable
Los atributos son nuevos atributos arrastrables en HTML5.
En HTML, a excepción de las imágenes, los enlaces y el texto seleccionado que se pueden arrastrar de forma predeterminada, otros elementos no se pueden arrastrar de forma predeterminada. Si desea que otros elementos se puedan arrastrar, primero debe draggable
establecer la propiedad en true
.
<p draggable="true"> 可拖拽</p>
复制代码
Una vez completada la configuración, es necesario combinar algunos eventos para completar el proceso de arrastrar y soltar:
- Eventos para arrastrar elementos
evento | temporización del disparador |
---|---|
dragstart |
Ejecutado una vez cuando comienza el arrastre |
drag |
Se activa varias veces después de que comienza el arrastre |
dragend |
Activado 1 vez después de arrastrar |
- Eventos que pueden soltar objetivos
evento | temporización del disparador |
---|---|
dragenter |
Ejecutado una vez al arrastrar un elemento a un objetivo que se puede soltar |
dragover |
Se activa varias veces al arrastrar un elemento a un destino que se puede soltar (una vez cada 100 milisegundos) |
drop |
Cuando el elemento arrastrado se suelta en el destino que se puede soltar (este evento solo tendrá efecto si se establece el arrastre) |
objetivo colocable
dragenter
o dragover
evento se puede utilizar para indicar destinos de colocación válidos, donde se puede colocar el elemento arrastrado.
La configuración para permitir que se coloque también requiere el bloqueo dragenter
y dragover
el manejo predeterminado de eventos.
<div ondragenter="event.preventDefault()">
复制代码
Haz un ejemplo para entender 可放置目标
:
objeto de transferencia de datos
DataTransfer
El objeto se utiliza para guardar los datos durante el proceso de arrastre, establecer el tipo de arrastre, etc. El objeto se puede obtener en las propiedades event
de todos los eventos de arrastre .dataTransfer
DataTransfer
dataTransfer.dropEffect
设置拖拽的操作类型。值必须是none
,copy
,link
或move
。
function dragover(e) {
e.preventDefault()
e.dataTransfer.dropEffect = 'move'
}
复制代码
- 传递数据 (不建议使用这种方法,可能有兼容问题)只能在
drop
事件中接收(测试的时候在其他拖拽事件中获取不到)
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
中 - 代码执行的逻辑是:列表项拖拽到可放置目标时,将该拖拽的元素从原位置删除,再将拖拽的元素插入到当前可放置目标的位置
代码如下:
<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>
内置组件,添加动画效果,让元素的过渡不会很生硬。
添加代码:
<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
npm i sortablejs -S
复制代码
使用 el-table
组件,写一个表格:
<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
:
<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
配置,并指定对应的样式名。
<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
样式的元素才可以被拖动。其他位置不能被拖动。
new Sortable(el, {
// ...
handle: '.handle-drag',
// ...
})
复制代码
vuedraggable
vue.draggable.next
是 Vue3 的拖拽组件,是基于 Sortable.js 实现的。可以用于拖拽列表、菜单、工作台、选项卡等常见的场景。
安装:
npm i -S vuedraggable@next
复制代码
使用:
<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
并定义一些基础数据。
<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
属性,可以实现在不同的块之间拖拽。
<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>
复制代码
相关地址
-
sortable.js github.com/SortableJS/…
-
vue.draggable.next https://github.com/SortableJS/vue.draggable.next
-
我的 Vue3 juejin.cn/column/7001…