主要做学习记录--原文
https://blog.csdn.net/weixin_45291937/article/details/125523244
学习成果--简单element-plus--表格封装:
1.因为element会废弃Pagination 事件---v-model和"事件"均有案例
效果图:
1.创建Table.vue
src/components/Table/index.vue
<template>
<div class="home">
<el-table
:border="true"
style="width: 100%"
height="100%"
:data="tableData"
:header-cell-style="{ backgroundColor: '#f5f5f5' }"
:cell-style="{ padding: '5px' }"
>
<template #empty>
<el-empty description="暂无数据"></el-empty>
</template>
<template v-for="column in columns" :key="column.prop || column.key">
<el-table-column
label="序号"
width="100"
:align="column.align"
v-if="column.label == '序号'"
>
<template #default="scope">
<slot name="xiuhao" :scope="scope">
<span
>{{
scope.$index +
(pagination.currentPage - 1) * pagination.pageSize +
1
}}
</span>
</slot>
</template>
</el-table-column>
<el-table-column
v-else-if="column.slot"
:label="column.label"
:width="column.width"
header-:align="column.align"
:align="column.align"
>
<template #default="scope">
<slot :name="column.slot" :scope="scope"></slot>
</template>
</el-table-column>
<el-table-column
v-else
:label="column.label"
:width="column.width"
:prop="column.prop"
show-overflow-tooltip
:align="column.align"
>
<template #default="{ row, $index }">
<!-- 对时间处理 -->
<template v-if="column.type === 'date'">
<span>{{
timeFormat(
row[column.prop as string],
column.dateFormat as string
)
}}</span>
</template>
</template></el-table-column
>
</template>
</el-table>
<!-- <div class="pagination">
<el-pagination
style="margin-top: 12px"
:current-page="pagination.currentPage"
:page-sizes="pagination.pageSizes"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
@size-change="pageSizeChange"
@current-change="currentPageChange"
prev-text="上一页"
next-text="下一页"
hide-on-single-page
>
</el-pagination>
</div> -->
<div class="pagination">
<el-pagination
style="margin-top: 12px"
v-model:current-page="pagination.currentPage"
v-model:page-sizes="pagination.pageSizes"
v-model:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
v-model:total="pagination.total"
hide-on-single-page
>
</el-pagination>
</div>
</div>
</template>
<script lang="ts" setup>
import { toRefs, reactive, watch } from "vue";
import { timeFormat } from "@/utils/common";
interface TableProps {
tableData: Array<object>; // table的数据
columns: Table.Column[]; // 每列的配置项
pagination: Table.Pagination; //页码
}
const props = defineProps<TableProps>();
interface EmitEvent {
(e: "selection-change", params: any): void; // 当选择项发生变化时会触发该事件
(e: "size-change", pageSize: number): void; // pageSize事件
(e: "current-change", currentPage: number): void; // currentPage按钮组事件
(e: "pagination-change", pagination: object): void; //pageSize事件和currentPage按钮组事件
}
// 使用 v-model 放弃elemntui-Pagination方法
// 监听 current-page , page-size 的改变,
const emit = defineEmits<EmitEvent>();
const { pagination } = toRefs(props);
watch(
() => pagination.value.currentPage,
(newValue, oldValue) => {
pagination.value.currentPage = newValue;
emit("pagination-change", pagination);
}
);
watch(
() => pagination.value.pageSize,
(newValue, oldValue) => {
pagination.value.pageSize = newValue;
pagination.value.currentPage = 1;
emit("pagination-change", pagination);
}
);
/*
* 注册分页 change 方法
*/
// const emit = defineEmits<EmitEvent>();
// const { pagination } = toRefs(props);
// // 切换pageSize
// const pageSizeChange = (pageSize: number) => {
// pagination.value.pageSize = pageSize;
// pagination.value.currentPage = 1;
// emit("pagination-change", pagination);
// };
// // 切换currentPage
// const currentPageChange = (currentPage: number) => {
// pagination.value.currentPage = currentPage;
// emit("pagination-change", pagination);
// };
</script>
<style lang="scss" scoped>
.home {
width: 100%;
height: 100%;
}
.pagination {
width: 100%;
display: flex;
margin-top: 10px;
justify-content: flex-end;
}
.el-tooltip__popper {
max-width: 20% !important;
}
.el-tooltip__popper,
.el-tooltip__popper.is-dark {
background: rgb(48, 65, 86) !important;
color: #fff !important;
line-height: 20px;
}
</style>
2.创建 index.d.ts 声明为全局的类型
src/components/Table/index.d.ts
// table表格
declare namespace Table {
type VNodeChild = import("vue").VNodeChild;
type Type = "selection" | "index" | "expand" | "image" | "date";
type Size = "large" | "default" | "small";
type Align = "center" | "left" | "right";
type Command = string | number;
type DateFormat =
| "yyyy-MM-dd"
| "yyyy-MM-dd hh:mm:ss"
| "yyyy-MM-DD hh:mm"
| "yyyy-MM";
type Order = "ascending" | "descending";
interface ButtonItem {
name: string;
command: Command;
size?: Size;
type?: "primary" | "success" | "warning" | "danger" | "info";
}
interface
interface Sort {
prop: string;
order: Order;
init?: any;
silent?: any;
}
interface Column {
// 对应列的类型。 如果设置了selection则显示多选框; 如果设置了 index 则显示该行的索引(从 1 开始计算); 如果设置了 expand 则显示为一个可展开的按钮
type?: Type;
label?: string;
prop?: string;
slot?: string;
width?: string;
align?: Align;
dateFormat?: DateFormat; // 显示在页面中的日期格式,简单列举了几种格式, 可自行配置
showOverflowTooltip?: boolean;
buttons?: ButtonItem[];
render?: (row?: Record<string, any>, index?: number) => VNodeChild; // 渲染函数,渲染这一列的每一行的单元格
sortable?: boolean | "custom"; // 对应列是否可以排序, 如果设置为 'custom',则代表用户希望远程排序,需要监听 Table 的 sort-change 事件
headerRender?: ({ column, index }) => VNodeChild; // 渲染函数,渲染列表头
headerSlot?: string; // 自定义表头插槽名字
children?: Column[]; // 配置多级表头的数据集合, 具体用法可参考多级表头使用示例。
}
interface Options {
height?: string | number;
// Table 的高度, 默认为自动高度。 如果 height 为 number 类型,单位 px;如果 height 为 string 类型,则这个高度会设置为 Table 的 style.height 的值,Table 的高度会受控于外部样式。
stripe?: boolean; // 是否为斑马纹 table
maxHeight?: string | number; // Table 的最大高度。 合法的值为数字或者单位为 px 的高度。
size?: Size; // Table 的尺寸
showHeader?: boolean; // 是否显示表头,
tooltipEffect?: "dark" | "light"; // tooltip effect 属性
showPagination?: boolean; // 是否展示分页器
paginationConfig?: Pagination; // 分页器配置项,详情见下方 paginationConfig 属性,
rowStyle?: ({ row, rowIndex }) => stirng | object; // 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。
headerCellStyle?: import("vue").CSSProperties; // 表头单元格的style样式,是一个object为所有表头单元格设置一样的 Style。注:CSSProperties类型就是一个对象,像正常在style中写css一样 {color: #f00}
defaultSort?: Sort; // 默认的排序列的 prop 和顺序。 它的 prop 属性指定默认的排序的列,order 指定默认排序的顺序。
rowKey?: string; // 行数据的 Key,用来优化 Table 的渲染。
}
interface Pagination {
total?: number; // 总条目数
currentPage: number; // 当前页数,支持 v-model 双向绑定
pageSize: number; // 每页显示条目个数,支持 v-model 双向绑定
pageSizes?: number[]; // 每页显示个数选择器的选项设置
layout?: string; // 组件布局,子组件名用逗号分隔
background?: boolean; // 是否为分页按钮添加背景色
}
}
3.创建 common.ts
src/utils/common.ts
**
* 时间戳转时间
* @param {Number} date 时间戳
* @param {String} format 需要的格式
* @return {String} 返回格式化完成时间
*/
interface timeFormat {
(date: Date | any, format: string): String;
}
export const timeFormat: timeFormat = (date, format) => {
date = new Date(date);
if (date == "Invalid Date") {
return "";
}
let map: any = {
M: date.getMonth() + 1, //月份
d: date.getDate(), //日
h: date.getHours(), //小时
m: date.getMinutes(), //分
s: date.getSeconds(), //秒
q: Math.floor((date.getMonth() + 3) / 3), //季度
S: date.getMilliseconds(), //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function (all: any, t: any) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = "0" + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === "y") {
return (date.getFullYear() + "").substr(4 - all.length);
}
return all;
});
return format;
};
4.引用
<template>
<div>
<!-- <div style="height: 400px">
<Table
:columns="tableColumn"
:table-data="tableData"
:pagination="pagination"
@pagination-change="paginationChange"
>
<template v-slot:xb="{ scope }">
<span> {{ scope.row.gender }}</span>
</template>
</Table>
</div> -->
<div style="height: 400px">
<Table
:columns="tableColumn"
:table-data="tableData"
v-model:pagination="pagination"
@pagination-change="paginationChange"
>
<template v-slot:xb="{ scope }">
<span> {{ scope.row.gender }}</span>
</template>
</Table>
</div>
</div>
</template>
<script setup lang="ts">
import Table from "@/components/Table/index.vue";
import { reactive } from "vue";
interface User {
date: number;
name: string;
address: string;
gender: number;
}
const tableData = reactive<User[]>([
{
date: 1660737564000,
name: "佘太君",
address: "上海市普陀区金沙江路 1516 弄",
gender: 0,
},
{
date: 1462291200000,
name: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
gender: 0,
},
{
date: 1462032000000,
name: "王小帅",
address: "上海市普陀区金沙江路 1519 弄",
gender: 1,
},
{
date: 1462204800000,
name: "王小呆",
address: "上海市普陀区金沙江路 1516 弄",
gender: 1,
},
{
date: 1462204800000,
name: "王小呆",
address: "上海市普陀区金沙江路 1516 弄",
gender: 1,
},
{
date: 1462204800000,
name: "王小呆",
address: "上海市普陀区金沙江路 1516 弄",
gender: 1,
},
{
date: 1462204800000,
name: "王小呆",
address: "上海市普陀区金沙江路 1516 弄",
gender: 1,
},
{
date: 1462204800000,
name: "王小呆",
address: "上海市普陀区金沙江路 1516 弄",
gender: 1,
},
{
date: 1462204800000,
name: "王小呆",
address: "上海市普陀区金沙江路 1516 弄",
gender: 1,
},
{
date: 1462204800000,
name: "王小呆",
address: "上海市普陀区金沙江路 1516 弄",
gender: 1,
},
]);
const tableColumn = reactive<Table.Column[]>([
{ label: "序号" },
{ prop: "name", width: "100", label: "名字", align: "center" },
{ prop: "gender", width: "100", label: "性别", slot: "xb", align: "center" },
{
prop: "address",
label: "地址",
headerSlot: "addressHeader",
showOverflowTooltip: true,
align: "center",
},
{
type: "date",
prop: "date",
label: "时间",
align: "center",
width: "150",
dateFormat: "yyyy-MM-dd",
},
]);
const pagination = reactive<Table.Pagination>({
total: 20,
currentPage: 1,
pageSize: 10,
pageSizes: [5, 10, 15, 20],
});
// table 传递的数据
const paginationChange = (res: any) => {
console.log(res.value,pagination.currentPage);
};
</script>
<style scoped></style>