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

简介: 使用ElementPlus实现内嵌表格和内嵌分页的Vue组件示例。

前言

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

一、示例代码

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

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

二、运行效果

目录
相关文章
|
4月前
element UI 组件封装--搜索表单(含插槽和内嵌组件)
element UI 组件封装--搜索表单(含插槽和内嵌组件)
129 5
|
4月前
|
JavaScript
js好用的动态分页插件
js好用的动态分页插件是一款简单的分页样式插件,支持样式类型,当前页,每页显示数量,按钮数量,总条数,上一页文字,下一页文字,输入框跳转等功能。
41 1
|
6月前
|
前端开发 JavaScript
vue实现通用分页控件,支持前端分页、后端分页。
vue实现通用分页控件,支持前端分页、后端分页。
86 1
|
XML 设计模式 前端开发
如何使用Thymeleaf给web项目中的网页渲染显示动态数据?(一)
如何使用Thymeleaf给web项目中的网页渲染显示动态数据?(一)
|
6月前
|
前端开发
【web组件库系列】纯CSS实现典型网页数据分页器
【web组件库系列】纯CSS实现典型网页数据分页器
89 0
|
6月前
|
JavaScript
Javaweb之Vue组件库Element案例分页工具栏的详细解析
4.4.3.5.3 分页工具栏 分页条我们之前做过,所以我们直接找到之前的案例,复制即可,代码如下: 其中template模块代码如下:
96 0
|
JavaScript 数据库 UED
Vue 的动态菜单表格数据展示以及分页查询实现
Vue 的动态菜单表格数据展示以及分页查询实现
140 0
|
JSON 小程序 前端开发
小程序模板语法样式与页面配置
小程序模板语法样式与页面配置
176 1
小程序模板语法样式与页面配置
|
数据可视化 JavaScript 前端开发
ElementUI实现表格内嵌进度条功能
ElementUI实现表格内嵌进度条功能
485 1