ant-design-vue 拖拽树形表格 vue3.0 ts

技术: ant-design-vue ts vue3.0

需求:

1.任意级进行表格拖拽
2.鼠标滑过进行编辑

效果图

在这里插入图片描述

原理:

ant的tree组件基础下进行改写

代码如下:

<template>
  <div class="basic-drop-tree-table">
    <div class="flex table-head">
      <div
        v-for="columnsItem in columns"
        :key="columnsItem.key"
        :style="countColWidth"
        class="table-box"
      >
        {{ columnsItem.title }}
      </div>
      <p class="table-head-action">操作</p>
    </div>
    <a-tree
      class="draggable-tree"
      draggable
      block-node
      :tree-data="gData"
      :fieldNames="fieldNames"
      :defaultExpandAll="true"
      @drop="onDrop"
    >
      <template #title="item">
        <div class="flex">
          <slot name="icon" :iconData="item"></slot>
          <div
            v-for="bb in columns"
            :key="bb.key"
            :style="countColWidth"
            class="table-box table-row-action"
          >
            <div v-if="item.change === true" class="flex input-width">
              <a-input
                :value="item[bb.key]"
                @change="inputChange($event, item, bb)"
                @press-enter="save(item)"
                @blur="save(item)"
              />
            </div>
            <div v-else>{{ item[bb.key] }}</div>
          </div>
          <div class="table-row-action">
            <a-button v-if="item.change === false" type="link" @click="actionFn(item)">
              编辑
            </a-button>
            <a-button v-else type="link" @click="save(item)">保存</a-button>
            <slot name="action" :item="item"></slot>
          </div>
        </div>
      </template>
    </a-tree>
  </div>
</template>
<script lang="ts" setup>
  import type { TreeProps } from 'ant-design-vue/es/tree';
  import useTreeData from '@/hooks/component/useTreeData';
  import { computed } from 'vue';
  const props = defineProps<{
    originDate: any[]; //原始表格数据
    treeData: TreeProps['treeData']; //树形表格数据
    fieldNames: TreeProps['fieldNames']; //替换字段
    columns: any[]; // 表头
  }>();
  const { onDrop, gData } = useTreeData(props.treeData, props.fieldNames);

  const countColWidth = computed(() => {
    return `width : calc( (100% - 150px) / ${props.columns.length} )`;
  });

  const emits = defineEmits<{
    (e: 'editableSave', treeData: TreeProps['treeData']): void;
  }>();
  //添加控制可编写状态
  props.originDate.forEach((item) => {
    item.change = false;
  });

  /**可编辑 */
  const inputChange = ($event, item, bb) => {
    item.data[bb.key] = $event.target.value;
    emits('editableSave', props.treeData);
  };
  const save = (item) => {
    item.data.change = false;
  };

  const actionFn = (item) => {
    item.data.change = true;
  };
</script>
<style lang="scss" scoped>
  .basic-drop-tree-table {
    border: 1px solid #f0f0f0;

    :deep(.ant-tree .ant-tree-treenode) {
      padding: 2px 0px;
      line-height: 40px;
      border-bottom: 1px solid #f0f0f0;

      &:last-child {
        border-bottom: none;
      }
    }

    :deep(.ant-tree-switcher) {
      margin: auto 0px;
    }

    .table-head {
      background: #fafafa;
      color: #000000d9;
      font-weight: 500;
      line-height: 40px;
      border-bottom: 1px solid #f0f0f0;
      padding-left: 24px;

      .table-head-action {
        margin: auto 0px;
      }
    }

    .table-row-action {
      display: flex;
      align-items: center;
    }

    .table-box {
      height: 40px;
      line-height: 40px;
      margin: auto 0px;
    }

    .input-width {
      width: 80%;
    }

    .tree-title {
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
  }
</style>

拖拽的hooks:

import type { AntTreeNodeDropEvent, TreeProps } from 'ant-design-vue/es/tree';
import { ref } from 'vue';

const useTreeData = (treeData: TreeProps['treeData'], fieldNames: TreeProps['fieldNames']) => {
  type TreeDataItem = any;
  const gData = ref<TreeProps['treeData']>(treeData);
  const onDrop = (info: AntTreeNodeDropEvent) => {
    const dropKey = info.node.key;
    const dragKey = info.dragNode.key; //拖拽的id值
    const dropPos = (info.node.pos as string).split('-');
    const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);

    const loop = (data: TreeProps['treeData'], key: string | number, callback: any) => {
      data?.forEach((item, index) => {
        if (item[fieldNames.key] === key) {
          return callback(item, index, data);
        }
        if (item.children) {
          return loop(item.children, key, callback);
        }
      });
    };
    const data = [...gData.value];
    // Find dragObject
    let dragObj: TreeDataItem;
    // 拖拽的那个值,拖拽值的索引,拖拽值所在的数组
    loop(data, dragKey, (item: TreeDataItem, index: number, arr: TreeProps['treeData']) => {
      arr?.splice(index, 1);
      dragObj = item;
    });

    if (!info.dropToGap) {
      // Drop on the content
      loop(data, dropKey, (item: TreeDataItem) => {
        item.children = item.children || [];
        /// where to insert 示例添加到头部,可以是随意位置
        item.children.unshift(dragObj);
      });
    } else if (
      (info.node.children || []).length > 0 && // Has children
      info.node.expanded && // Is expanded
      dropPosition === 1 // On the bottom gap
    ) {
      loop(data, dropKey, (item: TreeDataItem) => {
        item.children = item.children || [];
        // where to insert 示例添加到头部,可以是随意位置
        item.children.unshift(dragObj);
      });
    } else {
      let ar: TreeProps['treeData'] = [];
      let i = 0;
      loop(data, dropKey, (_item: TreeDataItem, index: number, arr: TreeProps['treeData']) => {
        ar = arr;
        i = index;
      });
      if (dropPosition === -1) {
        ar.splice(i, 0, dragObj);
      } else {
        ar.splice(i + 1, 0, dragObj);
      }
    }
    gData.value = data;
    console.log('data', data);
  };

  return { onDrop, gData };
};
export default useTreeData;

git :

git上面有案例
文件:src\views\table\ant\index.vue

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3Ant-Design-VueTree组件的用法与Vue2有些不同。以下是示例代码: ```html <template> <a-tree :tree-data="treeData" :draggable="true" :block-node="true" :show-line="true" :default-expanded-keys="defaultExpandedKeys" v-model:selected-keys="selectedKeys" @select="onSelect"> <template #title="{ key, title }"> <span> {{ title }} <a @click.stop="addNode(key)">Add</a> <a @click.stop="removeNode(key)">Delete</a> </span> </template> </a-tree> </template> <script> import { ref } from 'vue' export default { setup() { const treeData = ref([ { title: 'Parent 1', key: '0-0', children: [ { title: 'Child 1', key: '0-0-0' }, { title: 'Child 2', key: '0-0-1' } ] } ]) const defaultExpandedKeys = ref(['0-0']) const selectedKeys = ref([]) const addNode = (parentKey) => { const newNode = { title: 'New Node', key: `${parentKey}-${treeData.value.length}` } const parentNode = treeData.value.find(node => node.key === parentKey) if (!parentNode.children) { parentNode.children = [] } parentNode.children.push(newNode) treeData.value = [...treeData.value] } const removeNode = (key) => { const parentKey = key.split('-').slice(0, -1).join('-') const parentNode = treeData.value.find(node => node.key === parentKey) parentNode.children = parentNode.children.filter(node => node.key !== key) treeData.value = [...treeData.value] } const onSelect = (selectedKeys) => { console.log(selectedKeys) } return { treeData, defaultExpandedKeys, selectedKeys, addNode, removeNode, onSelect } } } </script> ``` 这个示例与Vue2的示例类似,只是我们使用Vue3的Composition API来编写代码。我们使用了ref函数来创建响应式变量。在addNode和removeNode方法,我们使用Vue3的响应式API来更新数据。当我们改变treeData的值时,我们必须通过解构赋值来创建一个新的数组来触发更新。注意,在Vue3,我们使用v-model来绑定selected-keys。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值