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

news2025/3/19 6:53:56

目录

一.项目文件结构

二.实现代码

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部分

<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: number
    date: string
    name: string
    address: 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 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 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部分

<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开始,需要加1
  const 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 = pageSize
  handInquire()
};
const handleCurrentPage = (currentPage: number) => {// 页码
  // console.log('handleCurrentPage', currentPage);
  formBtnList.currentPage = currentPage
  handInquire()
};
// 表格相关 结束

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字人本地部署之llama-本地推理模型

llama 本地服务命令 llama-server.exe -m "data/LLM/my.gguf" --port 8080 -m data/LLM/my.gguf -m 属于命令行选项&#xff0c;一般用来指定要加载的模型文件。 data/LLM/my.gguf 是模型文件的路径。gguf 格式的文件是一种用于存储语言模型权重的文件格式&…

RUOYI框架在实际项目中的应用三:Ruoyi微服务版本-RuoYi-Cloud

如需观看Ruoyi框架的整体介绍&#xff0c;请移步&#xff1a;RUOYI框架在实际项目中的应用一&#xff1a;ruoyi简介 一、Ruoyi微服务版本-Ruoyi微服务版本 1、官方资料 1&#xff1a;代码地址&#xff1a;https://gitee.com/y_project/RuoYi-Cloud.git 2&#xff1a;文档介绍…

linux操作系统3

1.安装桌面的centos操作系统 二.linux相对路径和绝对路径 1.相对路径:从当前目录开始数的不完整路径 2.绝对路径:从跟开始数的完整路径 (这2种路径主要是为了方便用户操作) 3.linux用户和用户组管理 创建用户组:useradd 删除用户:userdel 用户的修改:usermod(可以修改用…

windows创建开机启动任务

1、背景 一个java应用程序&#xff0c;需要做成开机启动&#xff0c;系统为windows系统。 2、创建启动脚本 创建一个 .bat 文件&#xff08;例如 startup.bat&#xff09;&#xff0c;并将其保存到 Java 应用程序的目录中&#xff08;如 E:\gitcode\mygit\learn\database\jdk2…

素数判定方法详解:从基础试除法到优化策略

素数是只能被1和自身整除的正整数。素数的判定是数论中的基础问题&#xff0c;也是算法竞赛中的常见考点。 一、知识点 素数的定义&#xff1a; 素数&#xff08;质数&#xff09;是大于1的自然数&#xff0c;且只能被1和自身整除。 试除法&#xff1a; 通过遍历从2到sqrt(n)​…

BFS,DFS带图详解+蓝桥杯算法题+经典例题

1.BFS和DFS的定义与实现方式 1.1 深度优先搜索&#xff08;DFS&#xff09; 基本概念&#xff1a;DFS 是一种用于遍历或搜索图或树的算法。它从起始节点开始&#xff0c;沿着一条路径尽可能深地探索下去&#xff0c;直到无法继续或者达到目标节点&#xff0c;然后回溯到上一个…

「清华大学、北京大学」DeepSeek 课件PPT专栏

你要的 这里都打包好啦&#xff0c;快快收藏起来&#xff01; 名称 链接 团队简介 类型 DeepSeek——从入门到精通 1️⃣ DeepSeek从入门到精通「清华团队」 清华大学新闻与传播学院 新媒体研究中心 元宇宙文化实验室 PPT课件 DeepSeek如何赋能职场应用? ——从提示语…

如何在 Github 上获得 1000 star?

作为程序员&#xff0c;Github 是第一个绕不开的网站。我们每天都在上面享受着开源带来的便利&#xff0c;我相信很多同学也想自己做一个开源项目&#xff0c;从而获得大家的关注。然而&#xff0c;理想很丰满&#xff0c;现实却是开发了很久的项目仍然无人问津。 最近&#x…

on-policy对比off-policy

目录 持续更新。。。 on-policy与off-policy的定义 Q-learning属于on-policy算法还是off-policy算法&#xff1f; 为什么off-policy适用于从离线经验或多种探索策略中学习&#xff0c;明明 On-policy 也可以基于探索学习的啊&#xff1f; 重要性权重方法 off-policy方法可…

基于SpringBoot+Vue的幼儿园管理系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、教师、普通用户功能模块&#xff1a;用户管理、教师管理、班级管理、幼儿信息管理、会议记录管理、待办事项、职工考核、请假信息、缴费信息、体检管理、资源管理、原料管理、菜品信息管理等技术选型&#xff1a;SpringBoot&#xff0…

案例5_3: 6位数码管静态显示

文章目录 文章介绍效果图仿真图复习知识&#xff1a;代码思考 文章介绍 第5章 学习数码管&#xff0c;使用6位数码管进行静态显示 效果图 仿真图 新建一个干净的5_3文件夹&#xff0c;用于存放新画的仿真图 除单片机最小系统外&#xff0c;新增3个元器件&#xff0c;分别是&…

Profinet转Modbus RTU/TCP以太网通讯处理器

Profinet转Modbus RTU/TCP以太网通讯处理器 在当今的工业自动化领域&#xff0c;各种通讯协议和标准层出不穷。 其中&#xff0c;Profinet和Modbus作为两种广泛应用的通讯协议&#xff0c;分别在不同的应用场景中发挥着重要作用。 然而&#xff0c;当需要将这两种协议进行转换…

3倍训练速度+40%显存节省!Mamba+Transformer 仅用一半时间,性能提升80%!

在人工智能领域&#xff0c;Mamba与Transformer的结合正在成为研究热点&#xff0c;为自然语言处理和多模态任务带来新的突破。 最新研究表明&#xff0c;通过将Mamba架构与Transformer的强大编码能力相结合&#xff0c;模型在处理复杂的多模态数据时的效率提升了50%&#xff…

春秋云境刷题1

CVE-2022-29464 靶标介绍&#xff1a; WSO2文件上传漏洞&#xff08;CVE-2022-29464&#xff09;是Orange Tsai发现的WSO2上的严重漏洞。该漏洞是一种未经身份验证的无限制任意文件上传&#xff0c;允许未经身份验证的攻击者通过上传恶意JSP文件在WSO2服务器上获得RCE。 Git…

台式机电脑组装---电源

台式机电脑组装—电源 22 33 主板供电是聚集了12V&#xff0c;5V,3.3V的24pin CPU供电的话主要是12V的44pin供电 44pin合并之后&#xff0c;就是8pin 55 SATA硬盘会使用饼io口取电&#xff0c;从电源获取12v,5v,3.3v的电 33

10-BST(二叉树)-建立二叉搜索树,并进行前中后遍历

题目 来源 3540. 二叉搜索树 - AcWing题库 思路 建立二叉搜索树&#xff08;注意传参时用到了引用&#xff0c;可以直接对root进行修改&#xff09;&#xff0c;同时进行递归遍历&#xff1b;遍历可以分前中后三种写&#xff0c;也可以用标志来代替合在一起。其余详见代码。…

蓝桥杯备考:贪心问题之淘淘摘苹果

这是淘淘摘苹果普通版&#xff0c;很可爱的一道题&#xff0c;我们不多陈述&#xff0c;直接上代码 #include <iostream> using namespace std; const int N 15; int a[N]; int main() {for(int i 1;i<10;i){cin >> a[i];}int x;cin >> x;x30;int cnt …

VSTO(C#)Excel开发 系列目录 含源码发布

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

Git使用和原理(3)

1.远程操作 1.1分布式版本控制系统 我们⽬前所说的所有内容&#xff08;⼯作区&#xff0c;暂存区&#xff0c;版本库等等&#xff09;&#xff0c;都是在本地&#xff01;也就是在你的笔记本或者 计算机上。⽽我们的 Git 其实是分布式版本控制系统&#xff01;什么意思呢&a…

博客图床 VsCode + PigGo + 阿里云OSS

关键字 写博客&#xff0c;图床&#xff0c;VsCode&#xff0c;PigGo&#xff0c;阿里云OSS 背景环境 我想把我在本地写的markdown文档直接搬到CSDN上和博客园上&#xff0c;但是图片上传遇到了问题。我需要手动到不同平台上传文件&#xff0c;非常耗费时间和经历。 为了解决…