Sortablejs动态同类型穿插

发布于:2025-06-26 ⋅ 阅读:(16) ⋅ 点赞:(0)

Sortablejs动态同类型穿插,非同类型禁止插入

文档:https://sortablejs.com/options
对应版本:

"sortablejs": "^1.15.0"
"vue": "2.6.10"
"element-ui": "2.13.2"

代码如下:

<template>
  <div>
    <el-table
      ref="dragTable"
      :data="tableData"
      row-key="id"
      border
      :row-class-name="tableRowClassName"
    >
      <el-table-column prop="id" label="ID" width="80" />
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="type" label="类型" />
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button class="drag-handle" type="text">拖拽按钮</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import Sortable from 'sortablejs'

export default {
  data() {
    return {
      tableData: [
        { id: 1, name: '行1', type: '取消推荐' },
        { id: 3, name: '行2', type: '取消推荐' },
        { id: 2, name: '行3(类型B)', type: '推荐' },
        { id: 4, name: '行4(类型B)', type: '推荐' }
      ],
      draggingType: null // 记录当前拖拽元素的类型
    }
  },
  mounted() {
    this.initSortable()
  },
  methods: {
    // 标记禁止拖入的行(可选)
    tableRowClassName({ row }) {
      return row.type === '取消推荐' ? 'recommend-drop-row' : ''
    },

    // 初始化拖拽
    initSortable() {
      const tbody = this.$refs.dragTable.$el.querySelector(
        '.el-table__body-wrapper tbody'
      )
      const self = this

      Sortable.create(tbody, {
        animation: 150,
        handle: '.drag-handle',
        ghostClass: 'ghost-row',
        group: {
          name: 'table-group',
          put: (evt) => {
            // 动态判断是否允许放入目标行
            const targetRow = evt.to.closest('tr')
            const targetType = targetRow.querySelector('td:nth-child(3)').textContent // 这里根据自己实际情况来调整
            return targetType === self.draggingType // 仅允许同类型放入
          }
        },
        onStart: (evt) => {
          // 拖拽开始时记录当前元素的类型
          const draggedRow = evt.item
          self.draggingType = draggedRow.querySelector('td:nth-child(3)').textContent
        },
        onMove: (evt) => {
          // 实时反馈是否允许插入(可选)
          const relatedRow = evt.related.closest('tr')
          if (relatedRow) {
            const relatedType = relatedRow.querySelector('td:nth-child(3)').textContent
            if (relatedType !== self.draggingType) {
              evt.dragged.style.opacity = '0.3' // 视觉提示
              return false // 禁止穿插
            }
          }
          return true
        },
        onEnd: (evt) => {
          // 重置状态
          self.draggingType = null
          evt.item.style.opacity = '1'

          // 数据顺序更新
          const { oldIndex, newIndex } = evt
          const movedRow = self.tableData.splice(oldIndex, 1)[0]
          self.tableData.splice(newIndex, 0, movedRow)
        }
      })
    }
  }
}
</script>

<style>
.recommend-drop-row {
  background-color: #d78e8e !important;
}
.ghost-row {
  opacity: 0.5;
  background: #c8ebfb !important;
}
.drag-handle {
  cursor: move;
}
</style>


网站公告

今日签到

点亮在社区的每一天
去签到