最近接到一个新需求,项目中(vue3)的所有列表都需要支持行可拖拽,这个重任落到了我身上,因为是内网开发,不能用npm下包,在package.json中找了找,好在找到了一个名为vuedraggable的包,版本是4.1.0,这个包不好用但也不难用吧,我也是第一次写这种需求也没个比较,凑合看吧。
项目中下载vuedraggable
npm i -S vuedraggable@next
页面中引入
import draggable from "vuedraggable"
接下来介绍一下一些比较常用的属性,这些属性都是百度的,如果有没有提到的,点开这里
| options | explain |
|---|---|
| v-model | 绑定的值,类似el-table中的data |
| animation | 动画时间 |
| tag | 你想把draggable标签渲染成什么标签 |
| disabled | 是否禁用 |
| item-key | 每个元素的 唯一标识,不需要加v-bind,写字符串就行 |
| list | 和v-model一样,但是不能同时用 |
| group | 组别,同组别之间可以互相拖拽 |
| drag-class | 被拖动的元素的类名 |
| scroll | 是否可以滚动 |
| handle | :handle=".mover" 只有当鼠标在class为mover类的元素上才能触发拖到事件 |
| filter | :filter=".unmover" 设置了unmover样式的元素不允许拖动 |
| fallback-class | 默认false,克隆选中元素的样式到跟随鼠标的样式 |
然后写俩方法
| event | explain |
|---|---|
| end | 拖拽结束之后 |
| start | 拖拽结束之后 |
| clone | 开启克隆,把拖拽变成复制 |
接下来是他的插槽,一共就三个
| template | explain |
|---|---|
| #header | 非必要,只能有一个子元素 |
| #item | 必要的,只能有一个子元素 |
| #footer | 非必要,只能有一个子元素 |
明白了它的属性接下来就简单了
//table.vue
<template>
<div class="app-content">
<table width="1100px" class="gridtable" borderColor="#000000" height="40" cellPadding="1" align="center" border="1">
<draggable v-model="tableDatas" animation="300" tag="tbody" @end="endDrag" ItemKey="prop">
<template #header>
<tr>
<th v-if="selection"></th>
<th v-for="item in tableHeader" :key="item.prop">{{ item.label }}</th>
</tr>
</template>
<template #item="{ element }">
<tr>
<td v-if="selection"><input type="checkbox" v-model="element.checked" @change="handleCheck(element)" /></td>
<td v-for="item in tableHeader" :key="item.prop">
<slot v-if="item.slot" :name="item.slot" :row="element"> </slot>
<span v-else>
{{ element[item.prop] }}
</span>
</td>
</tr>
</template>
</draggable>
</table>
</div>
</template>
<script setup>
import draggable from "vuedraggable"
const props = defineProps({
data: {
// 列表的数据
type: Array,
default: () => []
},
tableHeader: {
// 表头
type: Array,
default: () => []
},
selection: {
//是否开启多选
type: Boolean,
default: false
}
})
const emit = defineEmits(["selection-change"])
//操作多选框之后触发
const { data } = toRefs(props)
const tableDatas = ref(data.value)
const endDrag = () => {
// 拖拽动作结束后,大家自行发挥吧
}
const checkedList = computed(() => tableDatas.value.filter((item) => item.checked))
const handleCheck = (val) => {
emit("selection-change", checkedList.value, val)
}
</script>
<style scoped lang="scss">
//样式不会写555
.app-content {
table.gridtable {
width: 100%;
font-family: verdana, arial, sans-serif;
font-size: 11px;
color: #333333;
border-width: 1px;
border-color: #666666;
border-collapse: collapse;
}
table.gridtable th {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #dedede;
text-align: center;
}
table.gridtable td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #ffffff;
text-align: center;
}
}
</style>
这样基本el-table中的一些常用功能复刻下来了,如果不会用请参照elementui文档,不过我也没写啥复杂的,都很简单(难的我也写不出来555)
来个传入tableHeader的例子
[
{ prop: "name", label: "名字" },
{ prop: "ren", label: "人" },
{ prop: "uni", label: "部门" },
{ prop: "phone", label: "电话" },
{ prop: "skill", label: "技能" },
{ prop: "skill", label: "操作", slot: "handle" }
]
完结
有什么优化建议或者指导又或者问题请给我留言哦
对了,记得引入ref和computed、defineProps、defineEmits、toRefs,因为我用了unplugin-auto-import所以不需要引入,如果没下载这个包的同志还是需要引入的