el-transfer 穿梭框右侧实现拖拽排序功能

通过 sortablejs 工具库,自定义指令来实现拖拽。

npm i sortablejs

directives/draggableTransfer.ts

import Sortable from 'sortablejs'
export function draggableTransfer(app: any) {
  app.directive('draggable-transfer', (el, binding) => {
    const { value } = binding
    const transferDoms = el.querySelectorAll('.el-transfer-panel__list')
    transferDoms &&
      transferDoms.length > 1 &&
      Sortable.create(transferDoms[1], {
        handle: '.btn-action', // 触发拖动事件的元素,
        draggable: '.el-transfer-panel__item', // 拖动触发时,可拖动的区域
        animation: 150,
        sort: true,
        disabled: false,
        onEnd(event: any) {
          // 这里可以根据需要更新数据源,例如调用binding.value回调函数传递拖动信息
          binding.value?.onDragenChange(event.oldIndex, event.newIndex)
        }
      })
  })
}

directives/index.ts

import type { App } from 'vue'
import { draggableTransfer } from './draggableTransfer'

/**
 * 导出指令:v-xxx
 * @methods draggableTransfer 穿梭框右侧拖拽排序,用法: v-draggable-transfer
 */
export const setupAuth = (app: App<Element>) => {
  draggableTransfer(app)
}

/**
 * 导出指令:v-mountedFocus
 */
export const setupMountedFocus = (app: App<Element>) => {
  app.directive('mountedFocus', {
    mounted(el) {
      el.focus()
    }
  })
}

<template>
  <el-transfer
    v-draggable-transfer="{ onDragenChange }"
    v-model="leftTranList"
    :titles="['待选列表', '分类包含产品']"
    filterable
    :filter-method="filterMethod"
    filter-placeholder="搜索关键词"
    :data="tranData"
  >
    <template #default="{ option }">
      <div class="flex items-center justify-between">
        <div>{{ option.label }}</div>
        <img
          v-if="leftTranList?.some((e) => e === option.key)"
          src="@/assets/svgs/drag.svg"
          class="w-[20px] h-[20px] btn-action"
          alt=""
          srcset=""
        />
      </div>
    </template>
  </el-transfer>
</template>
<script setup lang="ts">
const tranData = ref<any>([
  {
    label: 'California',
    key: 0
  },
  {
    label: 'New York',
    key: 1
  },
  {
    label: 'Los Angeles',
    key: 2
  },
  {
    label: 'Chicago',
    key: 3
  },
  {
    label: 'Houston',
    key: 4
  },
  {
    label: 'Phoenix',
    key: 5
  },
  {
    label: 'San Antonio',
    key: 6
  },
  {
    label: 'Dallas',
    key: 7
  },
  {
    label: 'Miami',
    key: 8
  },
  {
    label: 'Seattle',
    key: 9
  },
  {
    label: 'Boston',
    key: 10
  }
])

const filterMethod = (query, item) => {
  return item.label.toLowerCase().includes(query.toLowerCase())
}
// 左侧穿梭框数据列表
const leftTranList = ref([])
// 拖拽指令回调
const onDragenChange = (newIndex: number, oldIndex: number) => {
  //拿出要移动的元素,并从原来的位置移除
  const value = leftTranList.value.splice(newIndex, 1)[0]
  //将元素插入到新的位置中
  leftTranList.value.splice(oldIndex, 0, value)
}
</script>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vue1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值