vxe-table 同时实现合并单元格与任意列展开行

发布于:2025-05-14 ⋅ 阅读:(11) ⋅ 点赞:(0)

 前一段时间有一个需求,要求既要合并单元格,又要实现树状图的效果,但是展开节点tree-node 可以放在非第一列的任意位置,Vxe-table可以实现如下是效果图:

大家可以一起交流学习!

~效果图

~Template

<template>
  <div>
    <p>
      <vxe-button @click="toggleExpandEvent">切换第一个</vxe-button>
      <vxe-button @click="setExpandEvent">展开第三个</vxe-button>
      <vxe-button @click="expandAllEvent">展开所有</vxe-button>
      <vxe-button @click="claseExpandEvent">关闭所有</vxe-button>
    </p>

    <vxe-table
      border
      show-overflow
      ref="tableRef"
      :column-config="{ resizable: true }"
      :tree-config="{ transform: true }"
      :edit-config="{ trigger: 'click', mode: 'cell' }"
      :data="tableData"
      :span-method="objectSpanMethod"
      header-row-class-name="headerRowClass"
    >
      <vxe-column
        field="userName"
        title="用户名"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.userName" />
        </template>
      </vxe-column>
      <vxe-column
        field="targetNum"
        title="数量"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.targetNum" mode="text" type="number" />
        </template>
      </vxe-column>
      <vxe-column
        field="dilieverSite"
        title="项目交付地"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.dilieverSite" mode="text" />
        </template>
      </vxe-column>
      <vxe-column
        field="name"
        title="名字"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
        tree-node
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.name" transfer />
        </template>
      </vxe-column>
      <vxe-column
        field="type"
        title="类型"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.type" transfer />
        </template>
      </vxe-column>
      <vxe-column
        field="size"
        title="尺寸"
        :edit-render="{ autofocus: ' .vxe-input--inner' }"
      >
        <template #edit="{ row }">
          <vxe-input v-model="row.size" transfer />
        </template>
      </vxe-column>
      <vxe-column title="删除小条目" width="80">
        <template #default="{ row }">
          <el-icon
            @click="handleERPDelete(row)"
            class="el-icon-delete"
            color="#F56C6C"
            ><Delete
          /></el-icon>
        </template>
      </vxe-column>
      <vxe-column field="oper" title="操作" width="100">
        <template #default="{ row }">
          <el-button @click="handleAdd(row)" link size="small" type="primary"
            >新增</el-button
          >
          <el-button @click="handleDelete(row)" link size="small" type="danger"
            >删除</el-button
          >
        </template>
      </vxe-column>
    </vxe-table>
  </div>
</template>

~script

<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { ElMessageBox } from "element-plus";
import type {
  VxeTablePropTypes,
  VxeTableEvents,
  VxeTableInstance
} from "vxe-table";
interface RowVO {
  id: number;
  userName: string;
  dilieverSite: string;
  targetNum: number;
  parentId: number | null;
  name: string;
  type: string;
  size: number;
  date: string;
  oper?: string;
}

const tableData = ref<RowVO[]>([
  {
    id: 10000,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc1",
    type: "mp3",
    size: 1024,
    date: "2020-08-01"
  },
  {
    id: 10050,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test2",
    type: "mp4",
    size: 0,
    date: "2021-04-01"
  },
  {
    id: 24300,
    parentId: 10050,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test3",
    type: "avi",
    size: 1024,
    date: "2020-03-01"
  },
  {
    id: 20045,
    parentId: 24300,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc4",
    type: "html",
    size: 600,
    date: "2021-04-01"
  },
  {
    id: 10053,
    parentId: 24300,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc96",
    type: "avi",
    size: 0,
    date: "2021-04-01"
  },
  {
    id: 24330,
    parentId: 10053,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc5",
    type: "txt",
    size: 25,
    date: "2021-10-01"
  },
  {
    id: 21011,
    parentId: 10053,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test6",
    type: "pdf",
    size: 512,
    date: "2020-01-01"
  },
  {
    id: 22200,
    parentId: 10053,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23666,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test8",
    type: "xlsx",
    size: 2048,
    date: "2020-11-01"
  },
  {
    id: 23677,
    parentId: 23666,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23671,
    parentId: 23677,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23672,
    parentId: 23677,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23688,
    parentId: 23666,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23681,
    parentId: 23688,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 23682,
    parentId: 23688,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 24555,
    parentId: null,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "test abc9",
    type: "avi",
    size: 224,
    date: "2020-10-01"
  },
  {
    id: 24566,
    parentId: 24555,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  },
  {
    id: 24577,
    parentId: 24555,
    userName: "宁夏宝丰",
    dilieverSite: "中国-灵武",
    targetNum: 3,
    name: "Test7",
    type: "js",
    size: 1024,
    date: "2021-06-01"
  }
]);

const setTabelRowSpan = (tableData: any, fieldArr: any, effectMerge = {}) => {
  let lastItem = {};
  fieldArr.forEach((field: any, index: any) => {
    let judgeArr = fieldArr.slice(0, index + 1);
    if (effectMerge[field]) {
      judgeArr = [...effectMerge[field], field];
    }
    tableData.forEach((item: any) => {
      item.mergeCell = fieldArr;
      const rowSpan = `rowspan_${field}`;
      if (
        judgeArr.every((e: any) => lastItem[e] === item[e] && item[e] !== "")
      ) {
        item[rowSpan] = 0;
        lastItem[rowSpan] += 1;
      } else {
        item[rowSpan] = 1;
        lastItem = item;
      }
    });
  });
};
const executeMerge = (data: any) => {
  // let effectRows = [0];
  // let fieldArr = ["userName"]; //全部字段
  let RowfieldArr = ["userName", "dilieverSite", "targetNum"];
  //setTableColumnSpan(data, fieldArr, effectRows); // (表格数据,表格字段,合并列
  setTabelRowSpan(data, RowfieldArr); // (表格数据,表格字段,合并的条件)
  //如果要用到合并条件:参考如下
  // const effectMerge = {
  //      dilieverSite: ['userName'],//参照userName字段合并
  //      targetNum: ['userName']//
  //  }
};

onMounted(() => {
  executeMerge(tableData.value);
});

const tableRef = ref<VxeTableInstance<RowVO>>();

const colspanMethod: VxeTablePropTypes.SpanMethod<RowVO> = ({
  row,
  _rowIndex,
  column,
  columnIndex
}) => {
  if (columnIndex === 1) {
    console.log("row", row);
  }
};

const toggleExpandEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.toggleTreeExpand(tableData.value[1]);
  }
};

const setExpandEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.setTreeExpand(tableData.value[8], true);
  }
};

const expandAllEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.setAllTreeExpand(true);
  }
};

const claseExpandEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    $table.clearTreeExpand();
  }
};

const objectSpanMethod: VxeTablePropTypes.SpanMethod<any> = ({
  row,
  column,
  rowIndex,
  columnIndex
}) => {
  // if (effectRows.includes(rowIndex)) {
  //   const colspan = row[`colspan_${column.property}`];
  //   if (colspan) {
  //     return { rowspan: 1, colspan: colspan };
  //   } else {
  //     return { rowspan: 0, colspan: 0 };
  //   }
  // }
  if (row.mergeCell.includes(column.property)) {
    const rowspan = row[`rowspan_${column.property}`];
    if (rowspan) {
      return { rowspan: rowspan, colspan: 1 };
    } else {
      return { rowspan: 0, colspan: 0 };
    }
  } else if (column.property === "oper") {
    const rowspan = row[`rowspan_userName`];
    if (rowspan) {
      return { rowspan: rowspan, colspan: 1 };
    } else {
      return { rowspan: 0, colspan: 0 };
    }
  }
};

const handleAdd = row => {
  console.log(row);
};

const handleDelete = row => {
  console.log(row);
};

const handleERPDelete = row => {
  ElMessageBox.confirm("确定要删除吗?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning"
  }).then(() => {
    console.log(row);
  });
};
</script>


网站公告

今日签到

点亮在社区的每一天
去签到