vue3+ts表格拖拽

vue3+ts表格拖拽

首先npm install vue-draggable-next

<template>
  <div style="display: flex" v-if="drag" class="draggable-btn">
    <el-form-item label="请输入跳转位置">
      <el-input v-model.number="num" @keydown.enter="handleChange(num)" style="width: 200px" maxLength="3"> </el-input>
    </el-form-item>
    <el-button type="primary" @click="handleChange(num)" class="ml-20">确认</el-button>
  </div>

  <div class="draggable-container" style="padding-bottom: 20px">
    <el-scrollbar max-height="calc(100vh - 280px)">
      <table class="drag-table" cellpadding="0" cellspacing="0">
        <thead class="drag-table-header">
          <tr>
            <template v-for="item in column" :key="item.label">
              <th>
                <div :style="{ width: item.width + 'px' }">
                  {
    
    {
    
     item.label }}
                </div>
              </th>
            </template>
          </tr>
        </thead>
        <draggable
          class="list-group"
          tag="tbody"
          v-model="ruleForm.tableData"
          v-bind="dragOptions"
          :move="onMove"
          @start="onStart"
          @end="onEnd"
          v-if="ruleForm.tableData?.length && drag"
        >
          <transition-group>
            <tr v-for="(item, index) in ruleForm.tableData" :key="index">
              <template v-for="i in column" :key="i.label">
                <td v-if="i.type === 'index'" :style="{ width: i.width + 'px' }">
                  <div>
                    <el-input
                      style="width: 50px"
                      type="text"
                      v-model.number="item.sort"
                      @change="
                        (val) => {
    
    
                          handleChange(val, index)
                        }
                      "
                    />
                  </div>
                </td>
                <td v-else-if="i.type === 'selection'" :style="{ width: i.width + 'px' }">
                  <div>
                    <el-checkbox v-model="item.check" />
                  </div>
                </td>
                <td v-else-if="i.type === 'slot'">
                  <div v-if="!item.whetherSpace || i.isOperation">
                    <slot :name="i.slot" :row="item" :index="index"> </slot>
                  </div>
                  <div v-else></div>
                </td>
                <td v-else :style="{ width: i.width + 'px' }">
                  <el-tooltip
                    class="box-item"
                    effect="dark"
                    :content="item[i.prop]"
                    placement="top"
                    v-if="i.is_tooltip && item[i.prop]"
                  >
                    <div class="ellipsis" :style="{ width: i.width + 'px' }">{
    
    {
    
     item[i.prop] }}</div>
                  </el-tooltip>
                  <div v-else>
                    {
    
    {
    
     item[i.prop] }}
                  </div>
                </td>
              </template>
            </tr>
          </transition-group>
        </draggable>
        <tbody class="list-group" tag="tbody" v-if="ruleForm.tableData?.length && !drag">
          <tr v-for="(item, index) in ruleForm.tableData" :key="index">
            <template v-for="i in column" :key="i.label">
              <td v-if="i.type === 'index'" :style="{ width: i.width + 'px' }">
                {
    
    {
    
     item.sort }}
              </td>
              <td v-else-if="i.type === 'selection'" :style="{ width: i.width + 'px' }">
                <div>
                  <el-checkbox v-model="item.check" />
                </div>
              </td>
              <td v-else-if="i.type === 'slot'">
                <div v-if="!item.whetherSpace || i.isOperation">
                  <slot :name="i.slot" :row="item" :index="index"> </slot>
                </div>
                <div v-else class="m-10"></div>
              </td>
              <td v-else :style="{ width: i.width + 'px' }">
                <el-tooltip
                  class="box-item"
                  effect="dark"
                  :content="item[i.prop]"
                  placement="top"
                  v-if="i.is_tooltip && item[i.prop]"
                >
                  <div class="ellipsis" :style="{ width: i.width + 'px' }">{
    
    {
    
     item[i.prop] }}</div>
                </el-tooltip>
                <div v-else>
                  {
    
    {
    
     item[i.prop] }}
                </div>
              </td>
            </template>
          </tr>
        </tbody>
        <tbody v-if="!ruleForm.tableData?.length">
          <tr>
            <td align="center" :colspan="column?.length || 0 + 2" class="ptb-10">暂无数据</td>
          </tr>
        </tbody>
      </table>
    </el-scrollbar>
  </div>
</template>

<script setup lang="ts">
import {
    
     ElMessage } from 'element-plus'
import {
    
     ref, computed, nextTick, inject, PropType } from 'vue'
import {
    
     VueDraggableNext as draggable } from 'vue-draggable-next'

defineProps({
    
    
  column: {
    
    
    type: Array as PropType<any[]>,
    default: () => []
  },
  drag: {
    
    
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['change'])
const dragOptions = computed(() => ({
    
    
  animation: 200,
  group: 'description',
  disabled: false,
  ghostClass: 'ghost'
}))

const num = ref()

const onMove = () => {
    
    }

const ruleForm: any = inject('ruleForm')

const onStart = () => {
    
    }

const onEnd = () => {
    
    
  ruleForm.value.tableData.forEach((i: any, index: number) => {
    
    
    i.sort = index + 1
  })
  emit('change')
}

const handleChange = (val?: any, index?: number) => {
    
    
  const reg = /^(([1-9])|([1-9]([0-9]+)))$/
  if (!reg.test(val)) {
    
    
    return ElMessage({
    
    
      type: 'warning',
      message: '只能是正整数'
    })
  }
  if (!val && val !== 0) {
    
    
    if (index) {
    
    
      ruleForm.value.tableData[index].sort = index + 1
    }
    return
  }
  if (val == 0) {
    
    
    return ElMessage({
    
    
      type: 'warning',
      message: '不能小于1'
    })
  }
  if (index) {
    
    
    const obj = ruleForm.value.tableData[index]
    ruleForm.value.tableData.splice(index, 1)
    ruleForm.value.tableData.splice(+val - 1, 0, obj) // 把原来的列数据添加到新的位置,然后再从原位置移除它,触发table的重绘
    ruleForm.value.tableData.forEach((i: any, index: number) => {
    
    
      i.sort = index + 1
      i.check = false
    })
  } else {
    
    
    const arr = ruleForm.value.tableData.filter((i: any) => i.check) // 排序选中的数据
    if (arr.length < 1)
      return ElMessage({
    
    
        type: 'warning',
        message: '请勾选排序所需数据'
      })
    arr.forEach((i: any) => {
    
    
      ruleForm.value.tableData.forEach((item: any, idx: number) => {
    
    
        if (item.processCode == i.processCode && item.sort == i.sort) {
    
    
          ruleForm.value.tableData.splice(idx, 1) // 删除选中的数据
        }
      })
    })
    ruleForm.value.tableData.splice(+val - 1, 0, ...arr) // 把原来的列数据添加到新的位置,然后再从原位置移除它,触发table的重绘
    ruleForm.value.tableData.forEach((i: any, index: number) => {
    
    
      i.sort = index + 1
      i.check = false
    })
  }
  num.value = null
  emit('change')
}

nextTick(() => {
    
    
  ruleForm.value.tableData.forEach((i: any, index: number) => {
    
    
    i.sort = index + 1
  })
})
</script>

<style scoped lang="scss">
.drag-table-header {
    
    
  /* display: flex; */
  /* justify-content: space-between; */
  background: #f5f7fa;
  color: #4a4a4a;
}

.drag-table-header th,
.drag-table tbody td {
    
    
  border-top: 1px #e6e6e6 solid;
  // border-left: 1px #ccc solid;
  // padding: 5px;
  overflow: hidden;
  // flex: 1;
  text-align: center;
  min-width: 50px;
  color: #4a4a4a;
}

.drag-table-header th > div {
    
    
  padding: 5px;
}
.drag-table tbody td > div {
    
    
  padding: 0px 5px;
}

.drag-table-header th:last-child,
.drag-table tbody td:last-child {
    
    
  /* flex: 1; */
  // border-right: 1px #ccc solid;
}

.drag-table {
    
    
  border-bottom: 1px #e6e6e6 solid;
  /* border-right: 1px #ccc solid; */
  width: 100%;
}

.draggable-container {
    
    
  // width: 100%;
  width: calc(100vw - 275px);
}
</style>

column的格式为

const columns = [
  {
    
     type: "selection", width: "50", label: "" },
  {
    
     type: "slot", prop: "partCode", label: "部件代码", slot: "partCode" },
  {
    
     prop: "partName", label: "部件名称" },
  {
    
     prop: "belongPartJoin", label: "所属部件" },
  {
    
     type: "slot", prop: "info", label: "基础信息", slot: "info" },
  {
    
     prop: "partDesc", label: "部件描述", showOverflowTooltip: true },
  {
    
     type: "slot", prop: "date", label: "日期信息", width: "350", slot: "date" },
  {
    
    
    width: "120",
    label: "日志",
    buttons: [{
    
     name: "日志", class: "btn-plain", command: "record", plain: true }],
  },
]

猜你喜欢

转载自blog.csdn.net/weixin_54722719/article/details/128183075