Vue3表格(Table)

news/2024/7/10 1:54:29 标签: typescript, less, vue

Vue2表格(Table)

可自定义设置以下属性:

  • 表格列的配置项(columns),类型:Array<{title?: string, width?: number, dataIndex?: string, slot?: string}>,默认 []

  • 表格数据数组(dataSource),类型:Array<any>,默认 []

  • 分页器配置(pagination),类型:object,默认 {}

  • 是否显示分页器(showPagination),类型:boolean,默认 false

  • 只有一页时是否隐藏分页器(hideOnSinglePage),类型:boolean,默认 false

  • 数据总数(total),类型:number,默认 0

  • 页面是否加载中(loading),类型:boolean,默认 false

效果如下图:

加载中样式:

展示数据样式:

无数据样式:

表格中使用到加载中组件(Spin)和分页组件(Pagination)

①创建表格组件Table.vue

<script setup lang="ts">
import Spin from '../spin'
import Pagination from '../pagination'
interface Column {
  title?: string // 列头显示文字
  width?: number // 列宽度
  dataIndex?: string // 列数据字符索引
  slot?: string // 列插槽名称索引
}
defineProps({
  columns: { // 表格列的配置项
    type: Array<Column>,
    default: () => []
  },
  dataSource: { // 表格数据数组
    type: Array<any>,
    default: () => []
  },
  pagination: { // 分页器配置
    type: Object,
    default: () => {
      return {}
    }
  },
  showPagination: { // 是否显示分页器
    type: Boolean,
    default: false,
  },
  hideOnSinglePage: { // 只有一页时是否隐藏分页器
    type: Boolean,
    default: false
  },
  total: { // 数据总数
    type: Number,
    default: 0
  },
  loading: { // 页面是否加载中
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(['change'])
function changePage (pager: {page: number, pageSize: number}) { // 分页器回调
  emit('change', pager)
}
</script>
<template>
  <div class="m-table-wrap">
    <table>
      <thead>
        <tr>
          <th :width="item.width" v-for="(item, index) in columns" :key="index">
            {{ item.title }}
          </th>
        </tr>
      </thead>
      <tbody class="m-body">
        <tr v-show="loading">
          <Spin class="m-loading" size="small" :colspan="columns.length" />
        </tr>
        <tr v-show="!total">
          <td class="m-empty" :colspan="columns.length">
            <svg class="u-empty-icon" viewBox="0 0 64 41" xmlns="http://www.w3.org/2000/svg">
              <g transform="translate(0 1)" fill="none" fillRule="evenodd">
                <ellipse fill="#F5F5F5" cx="32" cy="33" rx="32" ry="7"></ellipse>
                <g fillRule="nonzero" stroke="#D9D9D9">
                  <path d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"></path>
                  <path
                  d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
                  fill="#FAFAFA"
                  ></path>
                </g>
              </g>
            </svg>
            <p class="u-empty-desc">暂无数据</p>
          </td>
        </tr>
        <tr v-for="(data, index) in dataSource" :key="index">
          <td v-for="(col, ind) in columns" :key="ind" :title="data[col.dataIndex as any]">
            <slot v-if="col.slot" v-bind="data" :name="col.slot" :index="index">{{ data[col.dataIndex as any] || '--' }}</slot>
            <span v-else>{{ data[col.dataIndex as any] || '--' }}</span>
          </td>
        </tr>
      </tbody>
    </table>
    <Pagination
      class="mt20"
      @change="changePage"
      :current="pagination.page"
      :pageSize="pagination.pageSize"
      :total="total"
      :hideOnSinglePage="hideOnSinglePage"
      :showQuickJumper="true"
      :showTotal="true"
      placement="right"
      v-if="showPagination && total" />
  </div>
</template>
<style lang="less" scoped>
.m-table-wrap {
  color: rgba(0, 0, 0, 0.65);
  font-size: 14px;
  line-height: 1.5;
  table {
    table-layout: fixed;
    width: 100%;
    text-align: left;
    border-radius: 4px 4px 0 0;
    border-collapse: separate;
    border-spacing: 0;
    thead tr th {
      padding: 16px;
      color: rgba(0, 0, 0, 0.85);
      font-weight: 500;
      text-align: left;
      background: #fafafa;
      border-bottom: 1px solid #e8e8e8;
      transition: background .3s ease;
      &:first-child {
        border-top-left-radius: 4px;
      }
      &:last-child {
        border-top-right-radius: 4px;
      }
    }
    .m-body {
      position: relative;
      .m-loading {
        position: absolute;
        width: 100%;
        height: 100%;
      }
      .m-empty {
        padding: 48px 16px;
        color: rgba(0, 0, 0, 0.25);
        font-size: 14px;
        text-align: center;
        background: #fff;
        border-bottom: 1px solid #e8e8e8;
        border-radius: 0 0 2px 2px;
        .u-empty-icon {
          width: 64px;
          height: 41px;
          margin-bottom: 8px;
        }
        .u-empty-desc {
          color: rgba(0, 0, 0, 0.25);
          font-size: 14px;
        }
      }
    }
    tbody tr {
      transition: background .3s;
      td {
        padding: 16px;
        border-bottom: 1px solid #e8e8e8;
        transition: background .3s;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
      }
      &:hover {
        background: saturate(fade(@themeColor, 12%), 30%);
        
      }
    }
  }
}
</style>

②在要使用的页面引入:

<script setup lang="ts">
import { Table } from './Table.vue'
import { ref } from 'vue'
const loading = ref(false)
const total = ref(35)
const queryParams = ref({
        pageSize: 5,
        page: 1
      })
const columns = ref([
        {
          title: '名字',
          width: 100,
          dataIndex: 'name',
          slot: 'name'
        },
        {
          title: '年龄',
          width: 100,
          dataIndex: 'age'
        },
        {
          title: '职业',
          width: 100,
          dataIndex: 'job',
          slot: 'job'
        },
        {
          title: '性别',
          width: 100,
          dataIndex: 'sex'
        },
        {
          title: '地址',
          width: 120,
          dataIndex: 'address'
        }
      ])
const tableData = ref([
        {
          name: 'Stephen',
          age: 30,
          job: 'player',
          sex: '男',
          address: 'CaliforniaCaliforniaCaliforniaCaliforniaCaliforniaCalifornia'
        },
        {
          name: 'Leo',
          age: 36,
          job: 'actor',
          sex: '男',
          address: 'LA'
        },
        {
          name: 'Mr.Dear',
          age: 23,
          job: 'boy',
          sex: '男',
          address: 'Beijing'
        },
        {
          name: 'superman',
          age: 32,
          job: 'boy',
          sex: '男',
          address: 'US'
        }
      ])
function getData () {
  loading.value = true
  // 调用分页接口获取列表数据
}
function onChangeTable (pagination: {page: number, pageSize: number}) {
  console.log('pagination:', pagination)
  queryParams.value.page = pagination.page
  queryParams.value.pageSize = pagination.pageSize
  getData()
}
</script>
<template>
  <div>
    <h2 class="mb10">Table 表格基本使用</h2>
    <Table
      :columns="columns"
      :dataSource="tableData"
      :pagination="{
        page: queryParams.page,
        pageSize: queryParams.pageSize
      }"
      :showPagination="true"
      :hideOnSinglePage="false"
      :total="total"
      :loading="loading"
      @change="onChangeTable">
    <!-- 配置指定列数据 -->
    <template #name="record">
        hello {{ record.name }}
      </template>
      <template #job="{ job, index }">
        hi {{ job }}
      </template>
    </Table>
    <h2 class="mt30 mb10">加载中表格 (loading: true)</h2>
    <Table
      :columns="columns"
      :dataSource="[]"
      :pagination="{
        page: queryParams.page,
        pageSize: queryParams.pageSize
      }"
      :showPagination="true"
      :hideOnSinglePage="false"
      :total="0"
      :loading="true"
      @change="onChangeTable"
    ></Table>
    <h2 class="mt30 mb10">无数据表格 (total: 0)</h2>
    <Table
      :columns="columns"
      :dataSource="[]"
      :pagination="{
        page: queryParams.page,
        pageSize: queryParams.pageSize
      }"
      :showPagination="true"
      :hideOnSinglePage="false"
      :total="0"
      :loading="false"
      @change="onChangeTable"
    ></Table>
  </div>
</template>
<style lang="less" scoped>
</style>

http://www.niftyadmin.cn/n/233532.html

相关文章

Maven + Nexus 私有仓库搭建 + 项目推送 + 其他项目拉取(简记)

序 2022年是比较忙碌的一年&#xff0c;耽误了很多博客积累&#xff0c;这一年开始看的比写得多。后面也发现像原来一样的去写下来的成本太高。后面开始只做一些简记。即减少书写成本&#xff0c;也能巩固知识&#xff0c;提炼精华。 一 、Nexus下载 下载地址&#xff1a; N…

【Linux进阶篇】启动流程和服务管理

目录 &#x1f341;系统启动 &#x1f343;Init和Systemd的区别 &#x1f343;运行级别和说明 &#x1f341;Systemd服务管理 &#x1f343;6和7命令区别 &#x1f343;systemd常用命令 &#x1f341;系统计划调度任务 &#x1f343;一次性任务-at &#x1f343;batch &#x1…

插件化之APK动态加载

插件化相关概念&#xff1a; 根据组件化与插件化的区别来了解一下概念 组件化和插件化的区别 组件化:是将一个APP分成多个模块&#xff0c;每个模块都是一个组件(module)&#xff0c;开发的过程中我们可以让这些组件相互依赖或者单独调试部分组件&#xff0c;但是最终发布的…

14.Java面向对象----Object类

Object类 Java中Object 类是所有类的父类&#xff0c;也就是说 Java 的所有类都继承了 Object&#xff0c;子类可以使用 Object 的所有方法。 Object 类位于 java.lang 包中&#xff0c;编译时会自动导入&#xff0c;我们创建一个类时&#xff0c;如果没有明确继承一个父类&am…

X509证书以及相关java常用接口

二、X509证书 X.509证书是一种数字证书标准&#xff0c;用于验证在计算机网络中的身份认证。它们是由权威机构&#xff08;例如CA&#xff09;发行&#xff0c;包含有关证书持有者身份信息的数字签名。X.509证书通常用于SSL / TLS协议&#xff0c;以确保客户端和服务器之间的安…

【PyTorch】第九节:Softmax 函数与交叉熵函数

作者&#x1f575;️‍♂️&#xff1a;让机器理解语言か 专栏&#x1f387;&#xff1a;PyTorch 描述&#x1f3a8;&#xff1a;PyTorch 是一个基于 Torch 的 Python 开源机器学习库。 寄语&#x1f493;&#xff1a;&#x1f43e;没有白走的路&#xff0c;每一步都算数&#…

怎么远程控制电脑

为什么要从另一台电脑远程控制电脑&#xff1f; 如今&#xff0c;Splashtop已广泛应用于各个领域。 在很多情况下&#xff0c;您需要从另一台远程电脑控制一台电脑。 这里演示了两个例子&#xff1a; 1&#xff1a;当您不在同一楼层时&#xff0c;您的同事需要您的帮助来解决…

Flutter开发日常练习-小猫咪杂货店

贴三张效果图 1.欢迎页面 2.商品展示列表 3.购物车页面 因为数据是本地的所以创建本地数据 final List _shopItems [["ZaoShui.", "25.00", "assets/8b10de68e58cfef6bd5f22e5321537.jpg", Colors.green],["ZaoQi.", "25.0…