树形表格实现

微信图片_20241012143845.png

主要代码展示:
1、选择父级后子级联动的效果
2、表格样式

布局

 <el-table
        :data="tableData"
        style="width: 100%"
        :tree-props="{ children: 'children_prefix' }"
        row-key="pk"
        ref="treeTableRef"
        :default-expand-all="true"
        @select="handleSelect"
        @select-all="selectAll"
        id="tree-table"
      >
        <el-table-column type="selection" width="35" />
        <el-table-column v-for="item in columnsTable" :label="item.label" :key="item.label">
          <template #default="scope">
            <div
              class="treeSpan"
              :class="{ c1: scope.row._depth % 7 === 0, c2: scope.row._depth % 7 === 1, c3: scope.row._depth % 7 === 2 }"
            >
              <div
                class="treeSpanData link-text"
                v-if="item.name === 'prefix' || (item.name === '_children' && scope.row[item.name])"
                @click="toDetail(scope.row, item.name)"
              >
                {{ scope.row[item.name] || "-" }}
              </div>
              <div class="treeSpanData" v-else>
                {{ scope.row[item.name] || "-" }}
              </div>
            </div>
          </template>
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="190">
          <template #default="scope">
            <div
              class="treeSpan"
              :class="{ c1: scope.row._depth % 7 === 0, c2: scope.row._depth % 7 === 1, c3: scope.row._depth % 7 === 2 }"
            >
              <el-button type="primary" link :icon="Delete" @click="handleDeletePrefix(scope.row)">删除</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>

父子联动代码

const checkedData = ref<any>([]);
// 勾选变化
const handleSelect = (selection, row) => {
  // 更新当前行的选中状态
  const isSelected = selection.some(el => row.pk === el.pk);
  isSelected ? addId(row) : deleteId(row);
  if (row.children_prefix && row.children_prefix?.length) {
    toggleChildrenSelection(row.children_prefix, isSelected);
  }
  setSelect();
};

// 递归处理子级选中状态
const toggleChildrenSelection = (children, isChecked) => {
  children.forEach(child => {
    isChecked ? addId(child) : deleteId(child);
    if (child.children_prefix && child.children_prefix.length > 0) {
      toggleChildrenSelection(child.children_prefix, isChecked);
    }
  });
};
// 设置显示勾选
const setSelect = () => {
  nextTick(() => {
    treeTableRef.value!.clearSelection();
    checkedData.value.forEach(item => {
      treeTableRef.value!.toggleRowSelection(item, true);
    });
  });
};
// 全选和取消全选
const selectAll = () => {
  const isAllSelected = checkedData.value.length > 0;
  tableData.value.forEach(el => {
    if (isAllSelected) {
      deleteId(el); // 取消选择
      if (el.children_prefix && el.children_prefix.length > 0) {
        toggleChildrenSelection(el.children_prefix, false);
      }
    } else {
      addId(el); // 选择
      if (el.children_prefix && el.children_prefix.length > 0) {
        toggleChildrenSelection(el.children_prefix, true);
      }
    }
  });

  setSelect();
};

const addId = o => {
  const idSet = new Set(checkedData.value.map(item => item.pk));
  if (!idSet.has(o.pk)) {
    checkedData.value.push(o);
  }
};

const deleteId = o => {
  checkedData.value = checkedData.value.filter(item => item.pk !== o.pk);
};

样式

// 树形结构的表格样式
#tree-table {
  .link-text {
    color: #1775ff;
    cursor: pointer;
  }
  .el-table__cell {
    padding: 0;
  }
  .tr {
    background-color: #ffffff00;
  }
  .cell {
    display: flex;
    align-items: center;
    padding: 0 0 0 12px;
    line-height: 44px;
    .el-table__expand-icon {
      z-index: 100;
    }
    .treeSpan.c1 {
      position: relative;
      flex: 1;
      margin-left: -32px;
      background: rgb(245 248 255);
      .treeSpanData {
        margin-left: 32px;
      }
    }
    .treeSpan.c1::before {
      position: absolute;
      left: 0;
      width: 4px;
      height: 100%;
      content: "";
      background: rgb(23 117 255);
    }
    .treeSpan.c2 {
      position: relative;
      flex: 1;
      margin-left: -32px;
      background: rgb(250 243 238);
      .treeSpanData {
        margin-left: 32px;
      }
    }
    .treeSpan.c2::before {
      position: absolute;
      left: 0;
      width: 4px;
      height: 100%;
      content: "";
      background: rgb(255 117 19);
    }
    .treeSpan.c3 {
      position: relative;
      flex: 1;
      margin-left: -32px;
      background: rgb(243 252 249);
      .treeSpanData {
        margin-left: 32px;
      }
    }
    .treeSpan.c3::before {
      position: absolute;
      left: 0;
      width: 4px;
      height: 100%;
      content: "";
      background: rgb(18 199 146);
    }
  }
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容