大家好,我是一个8年前端开发经验的新博主(实战react方向较多),最近两年互联网行业动荡,工作不稳定,想积累点自己的项目实践经验以备不时之需。第一弹!分享一下最近使用vue3.0二次封装过的el-table组件,带有分页功能,以及操作列按动态数据有条件渲染!希望可以帮助各位在职前端小伙伴解决一些实际问题。
下一弹分享自定义搜索表单组件<SearchForm/>,喜欢的记得点个赞哦~
知识点:
1、二次封装el-table,减少重复写很多标签
2、table表格自带翻页页签pagination
3、序号列按当前页累加计算
4、操作列按数据有条件渲染
直接先看效果图:(前提先安装UI组件库:npm element-plus --save)
代码比较多,原因是我写的比较全,有经验的可以直接看关键的地方!!
首先,看二次封装过的Table组件代码
<!--
* @Author: Cocoon_xu
* @LastEditTime: 2024-02-18 16:41:12
* @Description: 二次封装表格组件,带翻页控件
-->
<template>
<!-- 表格 -->
<el-table
:data="tableData"
:border="border"
:stripe="stripe"
v-loading="loading"
style="width: 100%; overflow-x: auto;"
@selection-change="selectionChange"
>
<!-- 复选框 -->
<el-table-column v-if="isSelectabled" type="selection" width="50" />
<template v-for="(column,index) in tableColunms" :key="index">
<!-- 文字不需要特殊显示 -->
<el-table-column
:type="column.type"
:prop="column.prop"
:label="column.label"
:fixed="column.fixed || true"
:sortable="column.sortable || false"
:show-overflow-tooltip="column.overHidden || false"
:width="column.width"
:min-width="column.minWidth || '50px'"
:align="column.align || 'center'"
:formatter="column.formatter"
>
<!-- <template #default="scope" >
<span v-if="scope.column.type !=='index'">{{ scope.row[column.prop] ? scope.row[column.prop] : "" }}</span>
<span v-if="scope.column.type ==='index'">{{ (pagination.pageNum-1) * pagination.pageSize + scope.$index + 1}}</span>
</template> -->
</el-table-column>
</template>
<!-- 操作列插槽 -->
<el-table-column
label="操作"
fixed="right"
align="center"
>
<template #default="scope">
<!-- 当操作按钮少于3个,建议使用mode:'inline',默认为'dropdown'模式 -->
<table-dropdown
:actionColumns='()=>actionColumns(scope)'
:scope="scope"
:mode="actionMode || 'dropdown'"
/>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
v-model:page-size="pagination.pageSize"
v-model:current-page="pagination.pageNum"
:total="total"
:layout="layout"
:page-sizes="pageSizesArr"
@size-change="sizeChange"
@current-change="currentChange"
/>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
import TableDropdown from '@/components/TableDropdown/dropdown.vue'
const emits = defineEmits(['sizeChange', 'currentChange'])
const props = defineProps({
tableData:{
type: Array,
default:[]
},
tableColunms:{
type: Array,
default: []
},
actionColumns:{
type: Function,
default:() => {}
},
actionMode:{
type: String,
default: 'dropdown'
},
opColunms:{
type: Object,
default: {}
},
border:{ // 是否带有纵向边框
type: Boolean,
default: false
},
loading:{
type: Boolean,
default: false
},
isSelectabled: { // 是否带有复选框
type: Boolean,
default: false
},
pagination: {
type: Object,
default: () => {
return {pageSize: 10, pageNum: 1}
}
},
pageSizesArr:{
type: Array,
default: () => {
return [10,20,30,50]
}
},
stripe: { // 是否为斑马纹 table
type: Boolean,
default: false
},
total: {
type: Number,
required: true,
default: 0
},
layout:{
type: String,
default: "total, sizes, prev, pager, next, jumper"
}
})
// 触发选择框
const selectionChange = (val) => {
console.log(val)
}
// 切换分页size
const sizeChange = (val) => {
emits('sizeChange', val)
}
// 切换分页
const currentChange = (val) => {
emits('currentChange', val)
}
</script>
<style lang="scss">
/* .el-table .warning-row {
--el-table-tr-bg-color: var(--el-color-warning-light-9);
}
.el-table .success-row {
--el-table-tr-bg-color: var(--el-color-success-light-9);
} */
.pagination{
margin: 15px auto;
display: flex;
justify-content: center;
}
.el-table{
.el-table__header .cell{
color: #000;
}
}
</style>
我们可以看到Table组件里调用了TableDropdown,也是我自定义的一个组件,用于表格的操作列按表格数据有条件渲染成不同的按钮。下面为此组件的代码:
<!--
* @Author: Cocoon_xu
* @LastEditTime: 2024-02-18 16:38:25
* @Description: 表格操作列表
-->
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
actionColumns:{
type: Function,
default: () => {}
},
scope: {
type: Object,
default: {}
},
mode: {
type: String,
default: 'dropdown'
}
})
</script>
<template>
<template v-if="mode === 'inline'">
<el-button
v-for="(item,index) in actionColumns(scope)"
text
:key="index"
:icon="item.icon"
:disabled="item.disabled"
:style="{marginLeft:0, color: item.color}"
@click="(e)=>{
e.preventDefault();
let row = JSON.parse(JSON.stringify(scope.row))
item.event(row);
}"
>
{{ item.label }}
</el-button>
</template>
<template v-else>
<el-dropdown>
<span class="el-dropdown-link">
<el-icon color="#409EFC"><Menu/></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-for="(item, index) in actionColumns(scope)"
:key="index"
:icon="item.icon"
:disabled="item.disabled"
@click="(e)=>{
e.preventDefault();
let row = JSON.parse(JSON.stringify(scope.row))
item.event(row);
}"
>
<span>{{ item.label }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</template>
<style lang="scss">
.table-menu{
background: transparent;
.el-menu-item{
padding: 0;
height: 24px;
line-height: 24px;
}
}
</style>
最后,就是调用组件的使用
<!--
* @Author: Cocoon_xu
* @LastEditTime: 2024-02-18 16:38:25
* @Description: 组件调用
-->
<template>
<div class="table-box">
<common-table
:loading="loading"
:tableColunms="tableColunms"
:actionColumns="actionColumns"
:tableData="tableData"
:pagination="pagination"
:total="total"
:stripe="true"
:isSelectabled="false"
@currentChange="handleCurrentChange"
@sizeChange="handleSizeChange"
></common-table>
</div>
</template>
<script setup>
import { ref, onMounted, h } from 'vue';
import CommonTable from '@/components/Table/index.vue';
const loading = ref(false)
const tableData = ref([])
const total = ref(0)
const pagination = ref({
pageSize: 10,
pageNum: 1
})
const tableColunms = [
{
label:'序号',
width: 80,
formatter:(row, columm, cellValue, index) => {
return (pagination.value.pageNum-1) * pagination.value.pageSize + index + 1
}
},{
label:'标题',
prop:'title',
minWidth: 120,
overHidden: true
},{
label:'发布人',
prop:'sendByName',
},{
label:'审核状态',
prop:'submitStatus',
minWidth: 70,
formatter: (row, column, cellValue, index) => {
if(cellValue === '1'){
return h('span',{class:'draft'},'草稿')
}else if(row.auditStatus === 'active'){
return h('span',{class:'waitExamine'},'待审核')
}else if(row.auditStatus === 'completed'){
return h('span',{class:'pass'},'已通过')
}else if(row.auditStatus === 'terminated'){
return h('span',{class:'error'},'审批终止')
}else if(row.auditStatus === 'rejected'){
return h('span',{class:'error'},'被退回')
}else{
return '--'
}
}
}
]
// 操作列按钮
const actionColumns = (scope) =>{
let btns = [{
label:'查看',
type:'check',
icon:'View',
color:'#409EFC',
disabled: false,
event:(row) => {
console.log(row)
detail(row)
}
}];
if(scope.row.auditStatus == 1 || (scope.row.auditStatus == 'rejected')){
btns.push({
label:'编辑',
type:'edit',
icon:'Edit',
color:'#409EFC',
disabled: false,
event:(row) => {
console.log(row)
}
})
}
if((scope.row.sendStatus == 0 && scope.row.auditStatus != 'completed'))){
btns.push({
label:'删除',
type:'delete',
icon:'Delete',
color:'#409EFC',
disabled: false,
event:(row) => {
console.log(row)
}
})
}
return btns;
}
// 切换当前分页
const handleCurrentChange = (val) => {
pagination.value = {
pageNum: val,
pageSize: pagination.value.pageSize
}
getConListInfoPagefn();
}
// 切换分页size
const handleSizeChange = (val) => {
pagination.value = {
pageNum: 1,
pageSize: val
}
getConListInfoPagefn();
}
</script>
代码部分结束!希望对你有所帮助!