使用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>

二、运行效果

相关推荐
麻花201315 分钟前
WPF学习之路,控件的只读、是否可以、是否可见属性控制
服务器·前端·学习
.54815 分钟前
提取双栏pdf的文字时 输出文件顺序混乱
前端·pdf
jyl_sh23 分钟前
WebKit(适用2024年11月份版本)
前端·浏览器·客户端·webkit
zhanghaisong_20151 小时前
Caused by: org.attoparser.ParseException:
前端·javascript·html·thymeleaf
Eric_见嘉1 小时前
真的能无限试(白)用(嫖)cursor 吗?
前端·visual studio code
DK七七2 小时前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
老赵的博客2 小时前
QSS 设置bug
前端·bug·音视频
Chikaoya2 小时前
项目中用户数据获取遇到bug
前端·typescript·vue·bug
南城夏季2 小时前
蓝领招聘二期笔记
前端·javascript·笔记
Huazie2 小时前
来花个几分钟,轻松掌握 Hexo Diversity 主题配置内容
前端·javascript·hexo