vue3可拖拽表格组件

644 阅读2分钟

最近接到一个新需求,项目中(vue3)的所有列表都需要支持行可拖拽,这个重任落到了我身上,因为是内网开发,不能用npm下包,在package.json中找了找,好在找到了一个名为vuedraggable的包,版本是4.1.0,这个包不好用但也不难用吧,我也是第一次写这种需求也没个比较,凑合看吧。

项目中下载vuedraggable

npm i -S vuedraggable@next

页面中引入

import draggable from "vuedraggable"

接下来介绍一下一些比较常用的属性,这些属性都是百度的,如果有没有提到的,点开这里

optionsexplain
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,克隆选中元素的样式到跟随鼠标的样式

然后写俩方法

eventexplain
end拖拽结束之后
start拖拽结束之后
clone开启克隆,把拖拽变成复制

接下来是他的插槽,一共就三个

templateexplain
#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所以不需要引入,如果没下载这个包的同志还是需要引入的