vue3+Ts+elementPlus二次封装Table分页表格,表格内展示图片、switch开关、支持

ops/2025/3/18 12:43:57/

目录

一.项目文件结构

二.实现代码

1.子组件(表格组件)

 2.父组件(使用表格)


一.项目文件结构

1.表格组件(子组件)位置

2.使用表格组件的页面文件(父组件)位置

3.演示图片位置

elementPlus表格 Table 表格 | Element Plus

4.笑果演示

表格笑果

点击图片放大显示笑果

二.实现代码

1.子组件(表格组件)

1. src/views/Table.vue html部分

<!-- 表格区域 传值格式 -->
<!-- 单行文字:{ prop: 'inventory', label: '库存', width: '90' }, -->
<!-- 图片格式:{ prop: 'profile_picture_url', label: '商品主图', width: '110', isImg: true, height: 50 }, -->
<!-- 双行文字格式:{ prop: 'information', label: '商品信息', width: '140', doubleRow: true, text1: '货号', text2: '售价' }, -->
<!-- 开关格式:{ prop: 'listed', label: '是否上架', width: '110', isSwitch: true, }, -->
<el-table class="" v-loading="tableLoading" element-loading-text="Loading...":element-loading-spinner="svg" element-loading-svg-view-box="-10, -10, 50, 50"element-loading-background="rgba(122, 122, 122, 0.8)" border :data="paginatedData":default-sort="{ prop: 'date', order: 'descending' }" height="calc(100vh - 235px)":show-overflow-tooltip="true" @selection-change="handleSelectionChange"><el-table-column v-if="isSelected" type="selection" :selectable="selectable" width="55" /><el-table-column fixed align="center" label="序号" width="60"><template #default="scope">{{ scope.$index + 1 }}</template></el-table-column><el-table-column align="center" sortable v-for="(i, n) in columns" :key="n" :prop="i.prop" :label="i.label":formatter="i.formatter" :width="i.width"><template #default="scope"><!-- 当表头数据中有isImg为true时,使单元格展示图片(点击事件为放大显示) --><img class="image" v-if="i.isImg && scope.row[i.prop]" :src="scope.row[i.prop]" alt=""draggable="false" :style="`width: ${i.height}px; height: ${i.height}px`"@click="handleImageClick(scope.row[i.prop])" /><img v-else-if="i.isImg && !scope.row[i.prop]" src="@/assets/image/giegie.jpg" alt=""draggable="false" :style="`width: ${i.height}px; height: ${i.height}px`" /><span v-else-if="i.doubleRow"><span class="doubleRow">{{ i.text1 + ': ' }}</span> {{ scope.row.information?.text1 ?scope.row.information.text1 : '-' }}<br><span class="doubleRow">{{ i.text2 + ': ' }}</span> {{ scope.row.information?.text2 ?scope.row.information.text2 : '-' }}</span><el-switch v-else-if="i.isSwitch" active-text="" inactive-text="" active-color="#2fa1f1"inactive-color="#9c9c9c" v-model="scope.row[i.prop]" @change="handleStatusChange(scope.row)" /><span v-else>{{ formatCell(i, scope.row) }}</span></template></el-table-column><!-- 固定列 --><el-table-column v-if="isFixedColumn" fixed="right" align="center" label="操作" width="100"><template #default="scope"><el-button link type="primary" size="small" @click="btnListTable[0].click(scope.row, 1)">{{btnListTable[0].name}}</el-button><el-popover placement="bottom-start" trigger="click":popper-style="{ minWidth: '55px', padding: '10', width: 'auto', cursor: 'pointer' }"><template #reference><el-button link type="primary" size="small">更多</el-button></template><div><el-button v-for="(i, n) in btnListTable2" :key="n" link type="primary" size="small"@click="i.click(scope.row, 1)">{{i.name }}</el-button></div></el-popover></template></el-table-column></el-table>

js部分

javascript"><script setup lang='ts'>
import { ref, computed, defineProps, onMounted, defineEmits } from 'vue';
// 父传子
const props = defineProps({columns: {// 表头数据type: Array,validator: () => {return [];}},paginatedData: {// 表格数据type: Array,validator: () => {return [];}},btnListTable: {// 按钮组type: Array,validator: () => {return [];}},isFixedColumn: {// 是否有操作列type: Boolean,default: true},isSelected: {// 是否有选择框type: Boolean,default: false},tableLoading: {// 是否加载中type: Boolean,default: false,},
});// 操作列 更多按钮组
const btnListTable2 = ref(props.btnListTable.slice(1))
// 多选
interface User {id: numberdate: stringname: stringaddress: string
}
// 选择的内容
const multipleSelection = ref<User[]>([])
const selectable = (row: User) => ![1, 2].includes(row.id)
const handleSelectionChange = (val: User[]) => {multipleSelection.value = val
}
// 分页
const currentPage = ref(1);
const pageSize = ref(10);
const disabled = ref(false)
const background = ref(false)
const enlargedImageUrl = ref('');
const dialogVisible = ref(false);// 点击图片事件
const handleImageClick = (imageUrl: any) => {enlargedImageUrl.value = imageUrl;dialogVisible.value = true;
}// 子传父
const def = defineEmits(['pageSize', 'currentPage', 'switch']);// 分页事件 val: number
const handleSizeChange = () => {def('pageSize', pageSize.value)
}
const handleCurrentChange = () => {def('currentPage', currentPage.value)
}// 计算总数据条数
const totalData = computed(() => props.paginatedData.length);
// 开关事件
const handleStatusChange = ((row: any) => {def('switch', row)
})
// 加载中
const svg = `<path class="path" d="M 30 15L 28 17M 25.61 25.61A 15 15, 0, 0, 1, 15 30A 15 15, 0, 1, 1, 27.99 7.5L 15 15" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>`// 格式化单元格内容
const formatCell = (column: any, row: string) => {return column.formatter ? column.formatter(row) : row[column.prop];
}
</script>

 2.父组件(使用表格)

1.src/views/Dashboard.vue html部分

<template><div><Table :columns="columns" :paginatedData="paginatedData" :btnListTable="btnListTable":isFixedColumn="true" :tableLoading="loading" @pageSize="handlePageSize" @currentPage="handleCurrentPage"></Table></div>
</template>

 2.js部分

javascript"><script setup lang='ts'>
import { ref, reactive } from 'vue'
import type { FormRules } from 'element-plus'
import Table from '../components/Table.vue';
import DialogCom from '../components/DialogCom.vue';
import { list } from '../api/api.ts'
import { require } from '@/utils/require';
// 表格相关 开始
const loading = false
// 表头数据
const columns = ref([{ prop: 'user_id', label: '用户ID', width: 130 },{ prop: 'username', label: '用户名', width: 120 },{ prop: 'email', label: '邮件地址', width: 200 },{ prop: 'phone_number', label: '手机号码', width: 170 },{ prop: 'full_name', label: '真实姓名', width: 120 },{ prop: 'date_of_birth', label: '生日', width: 140 },{ prop: 'gender', label: '性别', width: 100 },{ prop: 'listed', label: '是否打篮球', width: '130', isSwitch: true, },{ prop: 'profile_picture_url', label: '头像', width: 90, isImg: true, height: 20 },// 当是否激活为true时,显示"是"{ prop: 'is_active', label: '是否激活', width: 120, formatter: (row: any) => row.is_active ? '是' : '否' },{ prop: 'created_at', label: '创建时间', width: 180, formatter: (row: any) => formattedDateTime(row.created_at) },{ prop: 'updated_at', label: '更新时间', width: 180 },
]);
// 表格数据
const paginatedData = ref([{ user_id: 'ID', username: '苏珊', email: 'singJumpRapBasketball@ikun.com', is_active: true, created_at: '2023-10-05T14:48:00.000Z', listed: true },{ user_id: 'ID', username: '打球被笑两年半', email: 'kunkun@ikun.com', is_active: false, created_at: '2023-10-05T14:48:00.000Z', profile_picture_url: require('@/assets/image/giegie.jpg') },
]);
// 查询条件
const formBtnList = reactive({pageSize: 10,currentPage: 1,
})
// 操作列按钮事件
const pricingDetail = () => {console.log('pricingDetail')
}
const reject = () => {console.log('reject')
}
// 操作列按钮组
const btnListTable = ref([{ name: '编辑', type: 'primary', click: pricingDetail },{ name: '添加账户', type: 'primary', click: reject },{ name: '导出', type: 'primary', click: reject },
])
// 处理日期时间 (ISO 8601 格式 如:2023-10-05T14:48:00.000Z )
const formattedDateTime = (dateData: string) => {const date = new Date(dateData);const year = date.getFullYear();const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1const day = String(date.getDate()).padStart(2, '0');const hours = String(date.getHours()).padStart(2, '0');const minutes = String(date.getMinutes()).padStart(2, '0');const seconds = String(date.getSeconds()).padStart(2, '0');return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 分页事件触发
const handlePageSize = (pageSize: number) => {// 每页大小// console.log('handlePageSize', pageSize);formBtnList.pageSize = pageSizehandInquire()
};
const handleCurrentPage = (currentPage: number) => {// 页码// console.log('handleCurrentPage', currentPage);formBtnList.currentPage = currentPagehandInquire()
};
// 表格相关 结束

以上,感谢观看,欢迎指正


http://www.ppmy.cn/ops/166763.html

相关文章

算法刷题整理合集(四)

本篇博客旨在记录自已的算法刷题练习成长&#xff0c;里面注有详细的代码注释以及和个人的思路想法&#xff0c;希望可以给同道之人些许帮助。本人也是算法小白&#xff0c;水平有限&#xff0c;如果文章中有什么错误或遗漏之处&#xff0c;望各位可以在评论区指正出来&#xf…

StarRocks SQL使用与MySql的差异及规范注意事项

StarRocks为OLAP列存数据库&#xff0c;擅长复杂分析查询&#xff0c;需显式定义分区/分桶键&#xff1b;MySQL为OLTP行存数据库&#xff0c;适合事务处理。SQL差异&#xff1a;StarRocks支持批量写入&#xff08;避免单行INSERT&#xff09;、物化视图优化&#xff0c;禁用LIM…

Python----计算机视觉处理(Opencv:图像缩放)

图像缩放 与图像旋转里的缩放的原理一样&#xff0c;图像缩放的原理也是根据需要将原图像的像素数量增加或减少&#xff0c;并通 过插值算法来计算新像素的像素值。 导入模块 import cv2 输入图像 imgcv2.imread(lena.png) 图像缩放 img_sizecv2.resize(img,None,fx0.5,fy0.5,…

Gone v2 Tracer 组件-给微服务提供统一的traceID

项目地址&#xff1a;https://github.com/gone-io/gone 原文地址&#xff1a;https://github.com/gone-io/goner/blob/main/tracer/README.md 文章目录 功能特性安装快速开始1. 加载追踪组件2. 使用追踪功能 实现方式性能测试API 参考Tracer 接口 高级用法在HTTP服务中使用在微…

React-state响应式内部数据(类组件Hook两种方式整理)

类组件 在类组件中要定义内部数据&#xff0c;由两种方案 构造器里面定义state属性&#xff0c;在这个对象中定义你需要的数据 constructor(){super()this.state {count:1}} 在类的下面直接定义一个属性state(推荐) state {count:10} 页面要使用state数据 <p>{t…

OSPF-5 3类LSA SummaryLSA

上一期我们介绍了2类LSA Network LSA的内容信息以及怎样从2类LSA中的信息描绘出一张具体的拓扑信息以及网段信息 这一期我们将介绍3类LSA Summary LSA区域间的LSA看看3类LSA是怎样把域间的路由信息传递到别的区域的 一、概述 由于3类LSA是用来描述我们域间的路由信息所以它是…

API自动化测试实战:Postman + Newman/Pytest的深度解析

引言 在数字化时代&#xff0c;API&#xff08;应用程序编程接口&#xff09;已成为系统间交互的核心纽带。无论是电商、金融、IoT还是云服务&#xff0c;API的稳定性、性能和安全性直接决定了产品的用户体验和业务连续性。然而&#xff0c;随着API复杂度的提升和迭代速度的加…

[GESP 202412 一级 T2] 奇数和偶数

描述 小杨有nn个正整数&#xff0c;他想知道其中的奇数有多少个&#xff0c;偶数有多少个。 输入描述 第一行包含一个正整数 nn&#xff0c;代表正整数个数。之后几行&#xff0c;每行包含一个正整数。 输出描述 输出两个正整数&#xff08;用英文空格间隔&#xff09;&am…