效果图


在这里插入图片描述
在这里插入图片描述

前置说明

本功能适用于Vue3+element plus,限制左侧不能拖拽排序

实现技术

原生web API dragstart、dragenter、dragend技术;为什么不使用vuedraggable plus?因为使用过程中,右侧新生成的数据项无法拖动

代码:

THML
<template>
  <el-transfer
    ref="sortableRef"
    v-model="rightData"
    filterable
    :filter-method="filterMethod"
    filter-placeholder="请输入"
    :data="data"
    @change="transferChange"
  >
    <template #default="{ option }">
      <div
        class="transferLable"
        :draggable="rightData.includes(option.key)"
        @dragstart="handleDragStart(option)"
        @dragenter="handleDragenter($event,option)"
        @dragend="handleDrop($event)"
      >
        <span class="trnsferValue">{{ option.label }}</span>
        <span
          id="draggable"
          class="sort"
        >
          <el-icon><Rank /></el-icon>
        </span>
      </div>
    </template>
  </el-transfer>
</template>
js
<script setup name="nurserItem">
import { ref } from 'vue'
import { Rank } from '@element-plus/icons-vue'

const data = ref([
  { key: 0, label: '11' },
  { key: 1, label: '22' },
  { key: 2, label: '33' },
  { key: 3, label: '44' },
  { key: 4, label: '55' },
  { key: 5, label: '66' }
])
const rightData = ref([])

const filterMethod = (query, item) => {
  if (!query) { return true }
  return item.label.includes(query)
}

// 往右侧添加时,手动添加头部
const transferChange = (_, direction, movedKeys) => {
  if (direction === 'right') {
    const arrList = data.value.filter(item => !movedKeys.includes(item.key))
    const arrUnshift = data.value.filter(item => movedKeys.includes(item.key))
    data.value = [...arrUnshift, ...arrList]
  }
}

let dragTarget = null // 用于存储被拖动的目标项
let dragIndex = -1 // 被拖动项在数组中的原始索引
let targetOption = null// 拖动过程中停放目标

// 开始拖动
const handleDragStart = (option) => {
  dragTarget = option
  dragIndex = data.value.findIndex(item => item === option)
}

// 放置时重新排序数组
const handleDragenter = (event, option) => {
  event.preventDefault()
  if (!dragTarget || !option) return
  targetOption = option
  if (event.target.draggable) {
    clearMovingDOM()
    const targetIndex = data.value.findIndex(item => item.key === targetOption.key)
    if (targetIndex < dragIndex) { // 往上拖拽
      event.target.className = 'movingTop'
    } else { // 往下拖拽
      event.target.className = 'movingBottom'
    }
  }
}

// 鼠标放开--拖拽结束
const handleDrop = () => {
  const targetIndex = data.value.findIndex(item => item.key === targetOption.key)
  const newIndex = targetIndex

  // 更新数组顺序
  const [removed] = data.value.splice(dragIndex, 1)
  data.value.splice(newIndex, 0, removed)

  // 重置拖动状态
  dragTarget = null
  targetOption = null
  dragIndex = -1
  clearMovingDOM()
}

// 清除moving Class名
const clearMovingDOM = () => {
  document.querySelectorAll('.movingBottom').forEach(Element => {
    Element.className = 'transferLable'
  })
  document.querySelectorAll('.movingTop').forEach(Element => {
    Element.className = 'transferLable'
  })
}
</script>

CSS
<style scoped lang="less">
::v-deep(.el-transfer-panel__item).el-checkbox {
  margin-right:10px;
  .transferLable{
    display: flex;
    justify-content: space-between !important;
  }
}
.el-transfer ::v-deep(.el-transfer-panel):first-child .sort{
  display: none;
}
.moving{
  border-bottom: 1px solid #409eff;
}
.movingTop{
  border-top: 1px solid #409eff;
}
.movingBottom{
  border-bottom: 1px solid #409eff;
}
</style>

备注:以上就是全部实现功能,有问题,大家可以私聊我。如有雷同,必将追究

GitHub 加速计划 / eleme / element
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45 7 个月前
a07f3a59 * Update transition.md * Update table.md * Update transition.md * Update table.md * Update transition.md * Update table.md * Update table.md * Update transition.md * Update popover.md 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐