Vue3表格(Table)
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><pathd="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><Paginationclass="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.pagequeryParams.value.pageSize = pagination.pageSizegetData()
}
</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>