目录
一.项目文件结构
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()
};
// 表格相关 结束
以上,感谢观看,欢迎指正