vue3+Ant Design Vue Transfer 穿梭框实现拖拽式列表

1,613 阅读2分钟

求点赞关注!!!!!!!!!!!!! 

CSDN博客:Fenゞ https://blog.csdn.net/weixin_49014702?type=blog

最近在写公司项目时需要在Ant Design Vue穿梭框右侧实现拖拽列表排序功能,而Ant Design Vue本身无此功能,所以自己写了一个,实现代码及原理如下:

//使用到VUE中的:
@dragstart 拖拽开始时在被拖拽元素上触发此事件
@drop.prevent 被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上
@dragover.prevent 拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上

1.Transfer 穿梭框HTML代码

<a-transfer :style="{width: '400px'}"  :data-source="mockData"
        :titles="['列表', '已选列表']" :disabled="disabled"
        :target-keys="formState.targetKeys" :selected-keys="transfer.selectedKeys"
        :render="item => item.title" @change="handleChange" @selectChange="handleSelectChange">
            <template #children="{direction,filteredItems,onItemSelect}">
              <div class="transfer">
              <div v-if="direction==='right'" class="transfer-right">
                <div draggable="true" v-for="(item,index) in filteredItems" :key="item.key"
                @mouseenter="isTarget(true,item)"
                @mouseleave="isTarget(false,item)"
                @dragstart="handleDragstart(index)"
                @drop.prevent="handleDrop()"
                @dragover.prevent="handleDragover(index)"
                @click="()=>checkChange(item.checked,item.key,onItemSelect)"
                 class="transfer-right-item"
                >
                <a-checkbox
                :checkedKeys="[...formState.targetKeys, ...transfer.selectedKeys]"
                 v-model:checked="item.checked"
                 ></a-checkbox>
                 <div class="transfer-right-item-content">
                  <span> &nbsp;{{item.title}}</span>
                  <MenuOutlined v-show="item.showMenu" />
                 </div>
                </div>
              </div>
              <div v-if="direction==='left'"  class="transfer-left">
                <div v-for="item in filteredItems" :key="item.key"  class="transfer-left-item"
                @click="()=>checkChange(item.checked,item.key,onItemSelect)">
                  <a-checkbox
                :checkedKeys="[...formState.targetKeys, ...transfer.selectedKeys]"
                 v-model:checked="item.checked"
                 ></a-checkbox>
                &nbsp; {{item.title}}
                </div>
              </div>
              </div>
            </template>
        </a-transfer>
// 选项在两栏之间转移时的回调函数
const handleChange = (nextTargetKeys, direction, moveKeys) => {
  moveKeys.forEach((item) => {
    drawerData.mockData.forEach((items, index) => {
      if (item === items.key)drawerData.mockData[index].checked = false;
    });
  });
  if (direction === 'right') {
    formState.targetKeys.push(...moveKeys);
  } else formState.targetKeys = nextTargetKeys;
};
// 选中项发生改变时的回调函数
const handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
  // 判断右边列表是否全选  是的话右边多选框全为true
  if (targetSelectedKeys.length === formState.targetKeys.length) {
    targetSelectedKeys.forEach((item) => {
      drawerData.mockData.forEach((items, index) => {
        if (item === items.key)drawerData.mockData[index].checked = true;
      });
    });
  }
  // 判断左边列表是否全选 是的话左边多选框全为true
  if (sourceSelectedKeys.length === drawerData.mockData.length - formState.targetKeys.length) {
    sourceSelectedKeys.forEach((item) => {
      drawerData.mockData.forEach((items, index) => {
        if (item === items.key)drawerData.mockData[index].checked = true;
      });
    });
  }
  drawerData.transfer.selectedKeys = [...sourceSelectedKeys, ...targetSelectedKeys];
};
const handleDrop = () => {
  // 删除老的
  const changeItem = formState.targetKeys.splice(drawerData.oldItemIndex, 1)[0];
  // 在列表中目标位置增加新的
  formState.targetKeys.splice(drawerData.newItemIndex, 0, changeItem);
};
const handleDragstart = (index) => { drawerData.oldItemIndex = index; };
const handleDragover = (index) => { drawerData.newItemIndex = index; };
// 用于判断选中了哪些多选框
const checkChange = (checked, key, onItemSelect) => {
  drawerData.mockData.forEach((items, index) => {
    if (key === items.key)drawerData.mockData[index].checked = !checked;
  });
  onItemSelect(key, !checked);
};
// 穿梭框列表图标显示与隐藏
const isTarget = (falg, e) => {
  let key = false;
  formState.targetKeys.forEach((item) => { if (e.key === item)key = item; });
  if (key !== false) {
    drawerData.mockData.forEach((item, index) => {
      if (e.key === item.key)drawerData.mockData[index].showMenu = falg;
    });
  }
};

3.Transfer 穿梭框样式代码 我使用的是less,大家可以根据自己的需求进行更改

:deep(.ant-transfer-list-body){
  width: 100px;
  height: 200px;
}
:deep(.ant-transfer-list-body-customize-wrapper){
  padding: 0 12px 0 0px;
  height: 100%;
}
.transfer{
  width: 178px;
   height: 200px;
  overflow: hidden;
}
.transfer-left,.transfer-right{
   width:100%;
   height: 200px;
  overflow-y: auto;
  &-item{
    padding-left: 12px;
     width: 100%;
    height: 30px;
    display: flex;
    align-items: center;
    &-content{
      width: 100%;
      display: flex;
      padding: 10px;
      align-items: center;
      justify-content: space-between;
    }
  }
  &-item:hover{
    background: #ccc;
  }
}