使用ElementPlus实现内嵌表格和内嵌分页

前言

有时遇到这样的需求,就是在表格里面嵌入一个表格,以及要求带有分页,这样在ElementPlus中很好实现。以下使用Vue2语法实现一个简单例子,毕竟Vue3兼容Vue2语法,若想要Vue3版本例子,简单改改就OK了。

一、示例代码

(1)/src/views/Example/InlineTable/index.vue

html 复制代码
<template>
  <div class="index" v-loading="elementLoading" element-loading-text="数据正在加载中...">

    <!-- 外层表格 -->
    <div class="outer-table-container">
      <el-table
        border
        size="small"
        row-key="id"
        ref="outerTableRef"
        height="100%"
        highlight-current-row
        :data="outerData.list"
        :expand-row-keys="outerData.expandedKeys"
        @expand-change="handleOuterDataExpandChange"
      >

        <el-table-column fixed prop="id" label="游戏服务器ID" width="200" align="center">
          <template #default="scope">
            <p>{{ scope.row.id }}</p>
          </template>
        </el-table-column>

        <el-table-column fixed prop="id" label="玩家列表" type="expand" width="200" align="center">
          <template #default="scope">
            <div class="outer-table-container-td__playerList" v-loading="scope.row.loading">
              <!-- ^ 内嵌表格 -->
              <div class="inner-table-container">
                <el-table
                  border
                  size="small"
                  row-key="id"
                  height="100%"
                  highlight-current-row
                  :data="scope.row.list"
                >
            
                  <el-table-column fixed prop="id" label="玩家ID" width="200" align="center">
                    <template #default="scope">
                      <p>{{ scope.row.id }}</p>
                    </template>
                  </el-table-column>
                  
                  <el-table-column prop="power" label="玩家战力" width="auto" align="center" show-overflow-tooltip>
                    <template #default="scope">
                      <p style="text-align: left; text-indent: 10px; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ scope.row.power }}</p>
                    </template>
                  </el-table-column>

                  <el-table-column fixed="right" label="操作" align="center" width="150">
                    <template #default="scope">
                      <div class="inner-table-container-td__operation">
                        <el-row>
                          <el-col :span="24">
                            <!-- ^ 查看详情 -->
                            <el-tooltip effect="dark" content="查看详情" placement="top" :enterable="false" :hide-after="0">
                              <el-button size="small" type="" style="border: unset" plain circle @click="
                                () => {
                                  log('查看详情 =>', scope.row)
                                }
                              ">
                                <el-icon :size="16"><View /></el-icon>
                              </el-button>
                            </el-tooltip>
                            <!-- / 查看详情 -->
                          </el-col>
                        </el-row>
                      </div>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
              <!-- / 内嵌表格 -->

              <!-- ^ 内嵌分页 -->
              <div class="inner-pagger-container">
                <el-pagination
                  v-if="scope.row.total > 0"
                  small
                  background
                  v-model:current-page="scope.row.pageNumber"
                  v-model:page-size="scope.row.pageSize"
                  :total="scope.row.total"
                  :page-sizes="[10, 20, 50, 100]"
                  layout="total, sizes, prev, pager, next, jumper"
                  @size-change="handleInnerTableSizeChange(scope.row)"
                  @current-change="handleInnerTableCurrentChange(scope.row)"
                />
              </div>
              
            </div>
          </template>
        </el-table-column>

        <el-table-column prop="host" label="游戏服务器名称" width="auto" min-width="400" align="center" show-overflow-tooltip>
          <template #default="scope">
            <p class="outer-table-container-td__name">{{ scope.row.host }}</p>
          </template>
        </el-table-column>

        <el-table-column label="创建时间" width="400" align="center">
          <template #default="scope">
            <div>{{ scope.row.createTime ? scope.row.createTime : '-' }}</div>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <!-- / 外层表格 -->

    <!-- 外层分页 -->
    <div class="outer-pagger-container">
      <el-pagination
        small
        background
        :current-page="outerData.pageNumber"
        :page-size="outerData.pageSize"
        :page-sizes="[20, 30, 50, 100]"
        :total="outerData.total"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleOuterTableSizeChange"
        @current-change="handleOuterTableCurrentChange"
      >
      </el-pagination>
    </div>
    <!-- / 外层分页 -->

  </div>
</template>

<script>
export default {
  data: () => ({

    // 加载标志
    elementLoading: true,

    // 外层数据
    outerData: {
      list: [], // 列表
      selectedList: [], // 已选列表
      expandedKeys: [], // 已展开键集合
      expandedList: [], // 已展开列表
      total: 521, // 总数
      pageNumber: 1, // 当前页
      pageSize: 20, // 页码大小
    },

    // 打印日志
    log: console.log
  }),
  created() {
    this.init()
  },
  mounted() {
  },
  methods: {
    // ---- ---- ---- ---- ^ 事件调用方法 ---- ---- ---- ----

    /**
     * 初始化外层表格
     */
    init() {
      const list = []
      for (let i = 0; i < this.outerData.pageSize; i++) {
        const number = parseInt(Math.random() * 10000) + i
        const row = {
          id: number,
          host: `游戏服务器 - ${number}`,
          createTime: new Date()
        }
        list.push(row)
      }
      this.outerData.list = list
      this.outerData.total = this.outerData.total
      this.elementLoading = false
    },

    /**
     * 外层表格 - 页码改变方法
     */
    handleOuterTableSizeChange(val) {
      this.elementLoading = true
      this.outerData.pageNumber = 1
      this.outerData.pageSize = val
      const frontRecords = this.outerData.pageSize * (this.outerData.pageNumber - 1)
      const remainRecords = this.outerData.total - frontRecords

      let list = []
      if (remainRecords >= this.outerData.pageSize) {  
        for (let i = 0; i < this.outerData.pageSize; i++) {
          const number = parseInt(Math.random() * 10000) + i
          const row = {
            id: number,
            host: `游戏服务器 - ${number}`,
            createTime: new Date()
          }
          list.push(row)
        }
      } else {
        for (let i = 0; i < remainRecords; i++) {
          const number = parseInt(Math.random() * 10000) + i
          const row = {
            id: number,
            host: `游戏服务器 - ${number}`,
            createTime: new Date()
          }
          list.push(row)
        }
      }

      setTimeout(() => {
        this.outerData.list = list
        this.outerData.total = this.outerData.total
        this.elementLoading = false
      }, 200)
    },

    /**
     * 外层表格 - 当前页改变方法
     */
    handleOuterTableCurrentChange(val) {
      this.elementLoading = true
      this.outerData.pageNumber = val
      const frontRecords = this.outerData.pageSize * (this.outerData.pageNumber - 1)
      const remainRecords = this.outerData.total - frontRecords
      
      let list = []
      if (remainRecords >= this.outerData.pageSize) {
        for (let i = 0; i < this.outerData.pageSize; i++) {
          const number = parseInt(Math.random() * 10000) + i
          const row = {
            id: number,
            host: `游戏服务器 - ${number}`,
            createTime: new Date()
          }
          list.push(row)
        }
      } else {
        for (let i = 0; i < remainRecords; i++) {
          const number = parseInt(Math.random() * 10000) + i
          const row = {
            id: number,
            host: `游戏服务器 - ${number}`,
            createTime: new Date()
          }
          list.push(row)
        }
      }

      setTimeout(() => {
        this.outerData.list = list
        this.outerData.total = this.outerData.total
        this.elementLoading = false
      }, 200)
    },

    /**
     * 外层表格 - 展开/收起某一行事件句柄方法
     */
    async handleOuterDataExpandChange(row, expandedRows) {
      this.outerData.expandedList = expandedRows
      const index = this.outerData.expandedList.findIndex((item) => item.id === row.id)
      if (index != -1) {
        // 展开
        this.getPlayerList(row)
      } else {
        // 收起
        row.loading = true
      }
    },

    /**
     * 根据游戏服务器获取玩家列表
     */
    async getPlayerList(row) {
      for (let vo of this.outerData.list) {
        // 匹配游戏服务器
        if (vo.id == row.id) {
          vo.loading = false
          vo.list = [] // 列表
          vo.total = 25 // 总数
          vo.pageNumber = 1 // 当前页
          vo.pageSize = 10 // 页码大小
          const list = []
          for (let i = 0; i < vo.pageSize; i++) {
            const number = parseInt(Math.random() * 100000000) + i
            const row = {
              id: number,
              power: Math.pow(number, 5),
            }
            list.push(row)
          }
          vo.list = list
        }
      }
    },

    /**
     * 内嵌表格 - 页码改变方法
     */
    handleInnerTableSizeChange(row) {
      row.loading = true
      row.pageNumber = 1
      const frontRecords = row.pageSize * (row.pageNumber - 1)
      const remainRecords = row.total - frontRecords
      
      let list = []
      if (remainRecords >= row.pageSize) {
        for (let i = 0; i < row.pageSize; i++) {
          const number = parseInt(Math.random() * 100000000) + i
          const row = {
            id: number,
            power: Math.pow(number, 5),
          }
          list.push(row)
        }
      } else {
        for (let i = 0; i < remainRecords; i++) {
          const number = parseInt(Math.random() * 100000000) + i
          const row = {
            id: number,
            power: Math.pow(number, 5),
          }
          list.push(row)
        }
      }

      setTimeout(() => {
        row.list = list
        row.total = row.total
        row.loading = false
      }, 200)
    },

    /**
     * 内嵌表格 - 当前页改变方法
     */
    handleInnerTableCurrentChange(row) {
      row.loading = true
      const frontRecords = row.pageSize * (row.pageNumber - 1)
      const remainRecords = row.total - frontRecords
      
      let list = []
      if (remainRecords >= row.pageSize) {
        for (let i = 0; i < row.pageSize; i++) {
          const number = parseInt(Math.random() * 100000000) + i
          const row = {
            id: number,
            power: Math.pow(number, 5),
          }
          list.push(row)
        }
      } else {
        for (let i = 0; i < remainRecords; i++) {
          const number = parseInt(Math.random() * 100000000) + i
          const row = {
            id: number,
            power: Math.pow(number, 5),
          }
          list.push(row)
        }
      }

      setTimeout(() => {
        row.list = list
        row.total = row.total
        row.loading = false
      }, 200)
    },
  }
}
</script>

<style lang="less" scoped>
  .index {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    overflow: hidden;

    // ---- ---- ---- ---- ^ 外层表格 样式 ---- ---- ---- ----
    :deep(.outer-table-container) {
      flex: 1;
      position: relative;
      overflow: hidden;

      .el-table {

        th {

          .cell {
            color: #000;
            font-weight: normal;
            font-size: 13px;
          }
        }

        td {
          padding: 2.5px 0;

          .cell {
            // color: #000;
            font-size: 13px;
            padding: 0;
          }
        }

        
        .outer-table-container-td__playerList {
          height: auto;
          overflow: auto;
          padding: 4px 7px;

          /* ^ 内嵌表格 */
          .inner-table-container {
            position: relative;
            overflow: hidden;

            .el-table {

              th {

                .cell {
                  color: #000;
                  font-weight: normal;
                  font-size: 13px;
                }
              }

              td {
                padding: 2.5px 0;

                .cell {
                  // color: #000;
                  font-size: 13px;
                  padding: 0;
                }
              }

              .el-table__cell {
                // background-color: #f8f8f8;
              }
            }

            /* 操作 */
            .inner-table-container-td__operation {

              .el-button {
                position: relative;
                margin: 0px 1px;
              }
            }
            /* / 操作 */
          }
          /* / 内嵌表格 */

          /* ^ 内嵌分页 */
          .inner-pagger-container {
            position: relative;
            width: 100%;
            height: 26px;
            margin-top: 7px;

            .el-pagination {
              position: absolute;
              top: 0;
              // left: 0;
              right: 0;
              bottom: 0;
              margin: 0 auto;
              width: fit-content;

              .btn-prev, .btn-next, .el-pager li {
                border: 1px solid #dcdfe6;
              }

              .el-pager li.is-active {
                border-color: #5e7ce0;
              }
            }
          }
          /* / 内嵌分页 */
        }

        /* 操作 */
        .operation {

          .el-button {
            position: relative;
            margin: 0px 1px;
          }
        }
        /* / 操作 */
      }
    }
    // ---- ---- ---- ---- / 外层表格 样式 ---- ---- ---- ----

    // ---- ---- ---- ---- ^ 外层分页 样式 ---- ---- ---- ----
    :deep(.outer-pagger-container) {
      padding: 7px 0;
      width: 100%;
      height: 26px;
      position: relative;

      .el-pagination {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        margin: 0 auto;
        width: fit-content;

        .btn-prev, .btn-next, .el-pager li {
          border: 1px solid #dcdfe6;
        }

        .el-pager li.is-active {
          border-color: #5e7ce0;
        }
      }
    }
    // ---- ---- ---- ---- / 外层分页 样式 ---- ---- ---- ----
  }
</style>

二、运行效果

相关推荐
GISer_Jing1 小时前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪2 小时前
CSS复习
前端·css
咖啡の猫4 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲6 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5817 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路7 小时前
GeoTools 读取影像元数据
前端
ssshooter8 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
Jerry8 小时前
Jetpack Compose 中的状态
前端
dae bal9 小时前
关于RSA和AES加密
前端·vue.js
柳杉9 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化