vue3.0+TS+antdesgin 选择树(tree)的增删改查(简单封装)

效果图:
在这里插入图片描述
父组件代码:

<div class="tree-box">
	<type-tree @onSelect="onSelect" :action="true"/>
</div>

子组件代码:

<template>
  <div class="tree">
    <a-tree
      show-line
      :treeData="treeData"
      :defaultExpandAll="true"
      @select.self="onSelect"
      v-if="treeData.length"
      :replaceFields="replaceFields"
      v-model:selectedKeys="selectedKeys"
    >
      <!-- @click.prevent="((e)=>{e.stopPropagation()})" :阻止默认事件向后传播 -->
      <template v-slot:title="nodeData">
        <a-input
          style="width: 100px"
          :ref="childId === nodeData.len ? 'inputVal' : 'inputTest'"
          @click.prevent="
            (e) => {
              e.stopPropagation();
            }
          "
          @blur="addSumbit(nodeData)"
          v-if="nodeData.isEdit"
          v-model:value="inputTypeName"
        />
        <span v-if="!nodeData.isEdit">{{ nodeData.typeName }}</span>
        <a-button-group class="editBox" v-if="action">
          <a-button type="link" size="small" @click.stop="slotAdd(nodeData)" title="添加">
            <template #icon><PlusOutlined /></template>
          </a-button>
          <a-button type="link" size="small" @click.stop="slotEdit(nodeData)" title="修改">
            <template #icon><EditOutlined /></template>
          </a-button>
          <a-button type="link" size="small" @click.stop="slotDelete(nodeData)" title="删除">
            <template #icon><DeleteTwoTone twoToneColor="#eb2f96" /></template>
          </a-button>
        </a-button-group>
      </template>
    </a-tree>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, ref, reactive, nextTick, createVNode } from 'vue';
import { SelectEvent } from 'ant-design-vue/es/tree/Tree';
import { adminApi, treeEdit } from '/@/api/index';
import { message, Modal } from 'ant-design-vue';
import {
  PlusOutlined,
  EditOutlined,
  DeleteTwoTone,
  ExclamationCircleOutlined,
} from '@ant-design/icons-vue';

export default defineComponent({
  props: {
    action: {
      type: Boolean,
      required: false,
    },
  },
  components: {
    PlusOutlined,
    EditOutlined,
    DeleteTwoTone,
  },
  setup(props, { emit }) {
    // 替换 treeNode 中 title,key,children 字段为 treeData 中对应的字段
    let replaceFields: object = reactive({
      title: 'typeName',
      key: 'id',
    });
    // 用于点击添加时总是让第一个输入框获取焦点
    let childId = ref(0);
    // tree的数据
    let treeData = ref([]);
    // 定义ref值
    let inputVal = ref<any>(null);
    let inputTest = ref<any>('inoputTest');
    // 输入框内容
    let inputTypeName = ref<string>('新建类型');
    // 刷新组件
    let flag = ref<boolean>(true);
    // 用于判断是点击添加还是编辑
    let editOperation = ref<string>('');
    onMounted(() => {
      getTreeData();
    });
    function onSelect(selectedKeys: string[], event: SelectEvent) {
      emit('onSelect', selectedKeys);
    }
    // 获取树列表
    async function getTreeData() {
      let tree: Array<object> = [];
      let tree1: Array<object> = [];
      let tree2: Array<object> = [];
      let res = await adminApi.TreeDataApi();
      res.obj.forEach((item: any) => {
        if (item.parentId === '0') {
          item.children = [];
          tree.push(item);
        }
        for (let node of tree) {
          getChildren(node, res.obj);
        }
      });
      tree.forEach((item: any) => {
        // 给数组里的每一个对象都添加一个isEdit属性
        item.isEdit = false;
        for (let i of item.children) {
          i.isEdit = false;
          tree1.push(i);
        }
        tree2.push(item);
        onSelect(item.id);
      });
      treeData.value = tree2;
    }
    function getChildren(node: any, dataList: any) {
      for (let item of dataList) {
        if (!item.children) {
          item.children = [];
        }
        if (item.parentId === node.id) {
          node.children.push(item);
        }
      }
      if (node.children === []) {
        return;
      }
      for (let child of node.children) {
        getChildren(child, dataList);
      }
    }
    // 点击添加按钮
    function slotAdd(nodeItem: any) {
      editOperation.value = 'add';
      let len = nodeItem.children.length || 0;
      childId.value = len;
      //  上面这里你看下
      nodeItem.children.unshift({
        len,
        id: null,
        isEdit: true,
        key: new Date().getTime(),
        parentId: nodeItem.id,
        children: [],
      });
      // 点击添加让新增的输入框获取焦点
      nextTick(() => {
        inputVal.value.focus();
      });
    }

    // 新增、编辑时input框失去焦点触发事件
    async function addSumbit(nodeItem: any) {
      let params = {
        id: nodeItem.id || null,
        parentId: nodeItem.parentId,
        typeName: inputTypeName.value,
      };
      let res =
        editOperation.value === 'add'
          ? await treeEdit.insertType(params)
          : await treeEdit.updateType(params);
      if (res.success) {
        nodeItem.isEdit = false;
        getTreeData();
        message.success(res.msg);
      } else {
        message.error(res.msg);
      }
    }
    // 点击编辑
    async function slotEdit(nodeItem: any) {
      editOperation.value = 'edit';
      treeData.value.forEach((item: any) => {
        if (item.id === nodeItem.id) {
          item.isEdit = true;
          inputTypeName.value = nodeItem.typeName;
        }
        for (let i of item.children) {
          if (i.id === nodeItem.id) {
            i.isEdit = true;
            inputTypeName.value = nodeItem.typeName;
          }
        }
        // 点击编辑时让输入框获取焦点
        nextTick(() => {
          inputTest.value.focus();
        });
      });
      console.log('nodeItem', nodeItem); //这是传点那个树的分支 传过来的树的属性
    }
    // 点击删除
    function slotDelete(nodeItem: any) {
      let params = {
        id: nodeItem.id,
      };
      Modal.confirm({
        title: '删除',
        icon: createVNode(ExclamationCircleOutlined),
        content: '你确定要删除吗?',
        okText: 'Yes',
        okType: 'danger',
        cancelText: 'No',
        async onOk() {
          const res = await treeEdit.deleteType(params);
          if (res.success) {
            getTreeData();
            message.success(res.msg);
          } else {
            message.error(res.msg);
          }
        },
      });
    }
    return {
      onSelect,
      treeData,
      replaceFields,
      slotAdd,
      slotEdit,
      slotDelete,
      childId,
      inputVal,
      inputTest,
      inputTypeName,
      addSumbit,
      flag,
      editOperation,
    };
  },
});
</script>
<style lang="scss" scoped>
.editBox {
  margin-left: 7px;
}
</style>

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐