目录

树形表格示例

树形表格示例

https://i-operation.csdnimg.cn/images/cf31225e169b4512917b2e77694eb0a2.pngVue 2实现树形表格

树形表格完整示例(Vue 2 + Element UI)

功能包含:

  • 展示父子层级结构
  • 支持展开/收起子项
  • 操作列(编辑、删除)
  • 自定义状态标签

示例代码


<template>
  <div class="tree-table-demo">
    <el-card>
      <el-table
        :data="menuTree"
        row-key="id"
        border
        style="width: 100%"
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      >
        <el-table-column prop="title" label="标题" />
        <el-table-column prop="type" label="类型" />
        <el-table-column prop="path" label="访问路径" />
        <el-table-column prop="route" label="路由地址" />
        <el-table-column prop="component" label="页面组件" />
        <el-table-column prop="status" label="状态">
          <template slot-scope="scope">
            <el-tag type="success">{{ scope.row.status }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="180">
          <template slot-scope="scope">
            <el-button type="text" size="small">编辑</el-button>
            <el-button type="text" size="small">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>

<script>
export default {
  name: 'TreeTableDemo',
  data() {
    return {
      menuTree: [
        {
          id: 1,
          title: '系统管理',
          type: '目录',
          path: '/system',
          route: '/system',
          component: '',
          status: '已注册',
          children: [
            {
              id: 2,
              title: '菜单管理',
              type: '菜单',
              path: '/system/menu',
              route: '/system/menu',
              component: 'SystemMenuList',
              status: '已注册',
              children: [
                {
                  id: 3,
                  title: '新增',
                  type: '按钮',
                  path: 'SystemMenuCreate',
                  route: 'SystemMenuCreate',
                  component: '',
                  status: '已注册'
                },
                {
                  id: 4,
                  title: '修改',
                  type: '按钮',
                  path: 'SystemMenuUpdate',
                  route: 'SystemMenuUpdate',
                  component: '',
                  status: '已注册'
                },
                {
                  id: 5,
                  title: '删除',
                  type: '按钮',
                  path: 'SystemMenuDelete',
                  route: 'SystemMenuDelete',
                  component: '',
                  status: '已注册'
                }
              ]
            },
            {
              id: 6,
              title: '角色管理',
              type: '菜单',
              path: '/system/role',
              route: '/system/role',
              component: '',
              status: '已注册'
            },
            {
              id: 7,
              title: '用户管理',
              type: '菜单',
              path: '/system/user',
              route: '/system/user',
              component: '',
              status: '已注册'
            }
          ]
        },
        {
          id: 8,
          title: '工作台',
          type: '页面',
          path: '/workspace',
          route: '/dashboard/workspace/index',
          component: '',
          status: '已注册'
        },
        {
          id: 9,
          title: '关于',
          type: '菜单',
          path: '/about',
          route: '/core/about/index',
          component: '',
          status: '已注册'
        }
      ]
    }
  }
}
</script>

<style scoped>
.tree-table-demo {
  padding: 20px;
}
</style>

https://i-blog.csdnimg.cn/direct/5aea0adab0ab4845bc5eb78fae90b08a.gif

补充说明

属性说明
row-key="id"必须设置唯一标识字段,用于识别每一行
tree-props指定子节点字段名(如 children)和是否有子节点的标志(可选)
嵌套结构数据结构中通过 children 字段嵌套子项
操作列可自定义按钮、图标、弹窗等交互

树形表格完整示例(Vue 2)

示例代码


<template>
  <div class="tree-table">
    <table>
      <thead>
        <tr>
          <th>标题</th>
          <th>类型</th>
          <th>访问路径</th>
          <th>路由地址</th>
          <th>页面组件</th>
          <th>状态</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="row in flatData" :key="row.id" v-show="isVisible(row)">
          <td :class="'indent-' + row.level">
            <span
              v-if="Array.isArray(row.children) && row.children.length"
              class="toggle"
              @click="toggle(row)"
            >
              {{ row.expanded ? '▼' : '▶' }}
            </span>
            {{ row.title }}
          </td>
          <td>{{ row.type }}</td>
          <td>{{ row.path }}</td>
          <td>{{ row.route }}</td>
          <td>{{ row.component }}</td>
          <td>
            <span :class="['tag', row.status === '已注册' ? 'success' : 'info']">
              {{ row.status }}
            </span>
          </td>
          <td>
            <button class="btn" @click="edit(row)">编辑</button>
            <button class="btn" @click="remove(row)">删除</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  name: 'TreeTable',
  data() {
    return {
      treeData: [
        {
          id: 1,
          title: '系统管理',
          type: '目录',
          path: '/system',
          route: '/system',
          component: '',
          status: '已注册',
          children: [
            {
              id: 2,
              title: '菜单管理',
              type: '菜单',
              path: '/system/menu',
              route: '/system/menu',
              component: 'SystemMenuList',
              status: '已注册',
              children: [
                {
                  id: 3,
                  title: '新增',
                  type: '按钮',
                  path: 'SystemMenuCreate',
                  route: 'SystemMenuCreate',
                  component: '',
                  status: '已注册'
                },
                {
                  id: 4,
                  title: '修改',
                  type: '按钮',
                  path: 'SystemMenuUpdate',
                  route: 'SystemMenuUpdate',
                  component: '',
                  status: '已注册'
                },
                {
                  id: 5,
                  title: '删除',
                  type: '按钮',
                  path: 'SystemMenuDelete',
                  route: 'SystemMenuDelete',
                  component: '',
                  status: '已注册'
                }
              ]
            },
            {
              id: 6,
              title: '角色管理',
              type: '菜单',
              path: '/system/role',
              route: '/system/role',
              component: '',
              status: '已注册'
            },
            {
              id: 7,
              title: '用户管理',
              type: '菜单',
              path: '/system/user',
              route: '/system/user',
              component: '',
              status: '已注册'
            }
          ]
        },
        {
          id: 8,
          title: '工作台',
          type: '页面',
          path: '/workspace',
          route: '/dashboard/workspace/index',
          component: '',
          status: '已注册'
        },
        {
          id: 9,
          title: '关于',
          type: '菜单',
          path: '/about',
          route: '/core/about/index',
          component: '',
          status: '已注册'
        }
      ],
      flatData: []
    }
  },
  created() {
    this.flatData = this.flattenTree(this.treeData)
  },
  methods: {
    flattenTree(nodes, level = 0, parent = null) {
      const result = []
      nodes.forEach(node => {
        this.$set(node, 'level', level)
        this.$set(node, 'parent', parent)
        this.$set(node, 'expanded', false)
        result.push(node)
        if (Array.isArray(node.children)) {
          result.push(...this.flattenTree(node.children, level + 1, node))
        }
      })
      return result
    },
    isVisible(row) {
      let parent = row.parent
      while (parent) {
        if (!parent.expanded) return false
        parent = parent.parent
      }
      return true
    },
    toggle(row) {
      row.expanded = !row.expanded
    },
    edit(row) {
      alert(`编辑:${row.title}`)
    },
    remove(row) {
      if (confirm(`确定删除 ${row.title} 吗?`)) {
        alert('删除成功(模拟)')
      }
    }
  }
}
</script>

<style scoped>
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
th, td {
  border: 1px solid #ddd;
  padding: 8px 12px;
  text-align: left;
}
.indent-0 { padding-left: 0; }
.indent-1 { padding-left: 20px; }
.indent-2 { padding-left: 40px; }
.indent-3 { padding-left: 60px; }
.toggle {
  cursor: pointer;
  margin-right: 5px;
  font-weight: bold;
}
.tag {
  display: inline-block;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 12px;
  color: #fff;
}
.success { background-color: #67c23a; }
.info { background-color: #909399; }
.btn {
  padding: 4px 8px;
  font-size: 12px;
  margin-right: 4px;
  cursor: pointer;
  border: none;
  border-radius: 4px;
  background-color: #409eff;
  color: white;
}
.btn:hover {
  background-color: #66b1ff;
}
</style>

https://i-blog.csdnimg.cn/direct/eed79a3de55446dda107a323bea461be.gif