• vue3 封装仿antdvue的Table组件基本实现


    最近需要在不使用UI框架的情况下封装一个简单的表格,由于对antd-vue比较熟悉,所以仿照了antd-vue的样子写了个简化版的Table组件。

    使用技术:VUE3、SCSS

    用过antd-vue的都应该知道table组件主要的传参是两个:columns和dataSource,分别对应表头信息和表格的数据信息。

    1.表头数据columns

    表头的传参数据结构如下:

    [
      { label: '姓名', key: 'name' },
      { label: '年龄', key: 'age' }
    ]
    
    • key:必须,用来标志当前行
    • label:非必须,当前列的列头显示内容

    子组件-表头的遍历:

    image.png

    2.表格数据dataSource

    表格数据传参的数据结构如下:

    [
      {name: '张三', age: 24},
      {name: '李四', age: 45}   
    ]
    

    可以看到dataSource里面的key都是columns里面的key字段对应的值

    对应源代码如下:

    image.png

    主要思路是先遍历每一行的数据,再在每一行的数据中根据columns遍历当前列的数据

    做到这里不加66行的代码的话,整个表格显示功能就已经实现了。

    3.添加操作功能

    其实整个功能做起来比较简单,现在回想起来,还是自己对vue3的slot使用不太熟悉。

    slot的基本使用见官网

    这里能实现这个功能主要看的是作用域插槽的部分

    代码还是看上面那张图的65、66两行。

    但是columns的传参需要有变化:

    [
      { label: '姓名', key: 'name' },
      { label: '年龄', key: 'age' },
      { label: '操作', key: 'operate', slots: 'operate'}   
    ]
    

    slots参数表示当前列需要使用插槽

    父组件使用table组件:

    <template #operate="record">
         <a @click="handleOperate(record.rowData)">详情</a>
    </template>
    

    注意:

    • operate是v-slot的简化写法

    • record是子组件内的slot插槽传过来的参数
    • rowData与Table组件的:rowData对应,即当前tr的内容

    接下来贴上使用代码:

    可以看到使用基本和antd-vue差别不大了

    4.其他功能

    目前已经实现了表头固定table可滚动、宽度等基本功能、如果需要添加其他功能的话可以在此基础上添加各种传参即可

    5.全部源码:

    <template>
      <div class="gw-table-content">
        <!-- 需要表头固定,且表格可以滚动时的表头 -->
        <table class="gw-fixed-table" v-if="tableHeaderFixed">
          <thead
            :style="{
              backgroundColor: headerBackground
                ? 'hsla(200, 79%, 49%, 0.2)'
                : 'transparent',
              fontSize: headerFontSize || '18px'
            }"
          >
            <th style="70px;" v-if="serialNumber">序号</th>
            <th
              :class="{ ellipsis: headerEllipsis }"
              :width="h.width"
              v-for="(h, i) in columns"
              :key="i"
            >
              {{ h.label }}
            </th>
          </thead>
        </table>
        <div class="un-fixed-table-box">
          <table class="gw-table">
            <!-- 正常的表头,无固定 -->
            <thead
              v-if="!tableHeaderFixed"
              :style="{
                backgroundColor: headerBackground
                  ? 'hsla(200, 79%, 49%, 0.2)'
                  : 'transparent',
                fontSize: headerFontSize || '18px'
              }"
            >
              <th style="70px;" v-if="serialNumber">序号</th>
              <th
                :class="{ ellipsis: headerEllipsis }"
                :width="h.width"
                v-for="(h, i) in columns"
                :key="i"
              >
                {{ h.label }}
              </th>
            </thead>
            <tbody>
              <tr
                :class="{ dash: trDash }"
                v-for="(tr, ri) in dataSource"
                :key="ri"
              >
                <!-- 是否需要序号 -->
                <td style="70px;" v-if="serialNumber">{{ ri + 1 }}</td>
                <td
                  :style="{
                    ...td.style,
                    padding: tdPadding,
                     td.width
                  }"
                  v-for="(td, key) in columns"
                  :key="key"
                >
                  <span :class="{ ellipsis: columnEllipsis }" :title="tr[td.key]">
                    <!-- 当前列的插槽, -->
                    <slot v-if="!td.slots">{{ tr[td.key] }}</slot>
                    <slot v-else :name="td.slots" :rowData="tr"></slot>
                    <!-- tr[td.key] 这个东西为什么能获取到当前这个key值的数据没太懂。。 -->
                  </span>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </template>
    
    <script lang="js">
    import { defineComponent } from 'vue'
    
    export default defineComponent({
      props: {
        columns: {
          // 表头
          required: true,
          default: []
        },
        dataSource: {
          // 表数据
          required: true,
          default: []
        },
        serialNumber: {
          // 是否需要第一列的序列号
          required: false,
          default: false
        },
        headerBackground: {
          // 是否需要表头的背景色
          required: false,
          default: false
        },
        headerFontSize: {
          // 表头字体大小
          required: false,
          default: ''
        },
        tdPadding: {
          // td的padding值
          required: false,
          default: ''
        },
        headerEllipsis: {
          // thead是否超过宽度省略
          required: false,
          default: true
        },
        columnEllipsis: {
          // td是否超过宽度省略
          required: false,
          default: true
        },
        trDash: {
          // 每行加下边框
          required: false,
          default: false
        },
        tableHeaderFixed: {
          // 表头是否固定
          required: false,
          default: false
        }
      }
    })
    </script>
    
    <style lang="scss" scoped>
    .gw-table-content {
      padding: 12px;
      height: calc(100% - 21px);
      .un-fixed-table-box {
        max-height: calc(100% - 44px);
        overflow-y: scroll;
      }
      .gw-table,
      .gw-fixed-table {
         100%;
        max-height: 100%;
        position: relative;
        table-layout: fixed;
        thead {
          background-color: #1ba0e1;
          color: #00aaff;
          font-family: 'Adobe Heiti Std R';
          font-size: 17px;
          th {
            padding: 10px 12px;
            font-family: Adobe Heiti Std;
            font-weight: normal;
            color: #00aaff;
          }
          th.ellipsis {
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
          }
        }
        tbody {
          tr:nth-child(odd) {
            background-color: rgba(27, 160, 225, 0.05);
          }
          tr {
            overflow: hidden;
            color: #00aaff;
            td {
              padding: 11px 12px;
              font-size: 14px;
              border-right: 2px solid transparent;
    
              > span {
                max- 100%;
                display: inline-block;
              }
              > span.ellipsis {
                overflow: hidden;
                white-space: nowrap;
                text-overflow: ellipsis;
              }
            }
          }
          tr.dash {
            border-bottom: 1px dashed rgba(#1ba0e1, 0.3);
          }
        }
      }
    }
    </style>
    
  • 相关阅读:
    Linux显示文件内容常用命令
    Linux文件权限和更改权限
    数据存储及恢复的基本原理
    使用jemter发送HTTPS请求
    运行Jmeter时,出现java.util.prefs.WindowsPreferences <init>异常警告
    Server08AD域安装以及推送
    SVN服务器和客户端搭建
    selenium常见操作
    TestNG 入门教程
    ant+TestNG-xslt生成selenium测试报告
  • 原文地址:https://www.cnblogs.com/codexlx/p/16392093.html
Copyright © 2020-2023  润新知