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

二、运行效果

目录
相关文章
Vue3框架中路由的使用和局部刷新的功能(第十一课)
Vue3框架中路由的使用和局部刷新的功能(第十一课)
867 0
Element el-select 选择器(下拉框)详解
本文目录 1. 用途 2. 数据绑定 2.1 固定选项 2.2 选项绑定数组 3. 功能效果 3.1 可清空选项 3.2 多选 3.3 可搜索 4. 事件响应 5. 小结
7330 0
Element el-select 选择器(下拉框)详解
|
JavaScript
Vue2文字提示(Tooltip)
这篇文章介绍了如何在Vue 3框架中创建一个文字提示组件(Tooltip),允许自定义提示框的最大宽度、展示文本和提示文本,支持鼠标悬停显示和隐藏效果。
561 0
Vue2文字提示(Tooltip)
|
数据格式
使用小技巧实现el-table组件的合并行功能,ElementUI和ElementPlus都适用
本文介绍了在ElementUI和ElementPlus中使用`el-table`组件实现合并行功能的技巧,包括多列合并和单列合并的方法,并提供了相应的示例代码和运行效果。
9971 1
使用小技巧实现el-table组件的合并行功能,ElementUI和ElementPlus都适用
|
资源调度 JavaScript API
【Vue2 / Vue3】 一个贼nb,贼强大的自定义打印插件
【Vue2 / Vue3】 一个贼nb,贼强大的自定义打印插件
10285 120
|
JavaScript UED
Vue + ElementUI 实现动态添加和删除表单项的多层嵌套表单
【10月更文挑战第5天】本示例展示了如何在 Vue.js 中使用 Element UI 组件实现动态添加和删除嵌套表单项。该表单包含设备信息、设备部位及其对应的任务列表,支持用户动态添加设备部位和任务,并提供相应的表单验证规则。
1627 0
Vue + ElementUI 实现动态添加和删除表单项的多层嵌套表单
|
JavaScript
如何对ElementUI、ElementPlus中的Tree树组件进行美化,如增加辅助线、替换展开收起图标、点击节点后文字高亮等效果?本文给你答案!
本文介绍了如何对ElementUI和ElementPlus的Tree树组件进行美化,包括增加辅助线、替换展开收起图标、点击节点后文字高亮等效果,并提供了详细的代码示例和实现效果。
3631 0
如何对ElementUI、ElementPlus中的Tree树组件进行美化,如增加辅助线、替换展开收起图标、点击节点后文字高亮等效果?本文给你答案!
|
监控 前端开发 JavaScript
React 静态网站生成工具 Next.js 入门指南
【10月更文挑战第20天】Next.js 是一个基于 React 的服务器端渲染框架,由 Vercel 开发。本文从基础概念出发,逐步探讨 Next.js 的常见问题、易错点及解决方法,并通过具体代码示例进行说明,帮助开发者快速构建高性能的 Web 应用。
577 10
|
JavaScript 前端开发
vue3教程,如何手动获取后端数据(入门到精通3,新人必学篇)
本文提供了一个Vue 3教程,讲解了如何使用axios库手动从后端获取数据,包括安装axios、配置后端访问地址、编写路由地址、发起HTTP请求以及在组件中读取和打印响应数据的步骤。
2121 0
vue3教程,如何手动获取后端数据(入门到精通3,新人必学篇)
|
前端开发 虚拟化
简单记录使用 ElementPlus 的虚拟化树形控件(el-tree-v2)心得
这篇文章分享了作者使用ElementPlus的虚拟化树形控件`el-tree-v2`的心得,展示了其基本用法和如何通过自定义模板来增强树节点的交互性。
4083 1
简单记录使用 ElementPlus 的虚拟化树形控件(el-tree-v2)心得