效果如下:
ok,开始代码,逻辑肯定是公共部分写死,不一样的地方用插槽来完成
table.vue
<template>
<div class="hy-table">
<div class="header">
<slot name="header">
<div class="title">{{ title }}</div>
<div class="handler">
<slot name="headerHandler"></slot>
</div>
</slot>
</div>
<el-table
:data="listData"
border
style="width: 100%"
@selection-change="handleSelectionChange"
v-bind="childrenProps"
>
<el-table-column
v-if="showSelectColumn"
type="selection"
align="center"
width="60"
></el-table-column>
<el-table-column
v-if="showIndexColumn"
type="index"
label="序号"
align="center"
width="80"
></el-table-column>
<template v-for="propItem in propList" :key="propItem.prop">
<el-table-column v-bind="propItem" align="center" show-overflow-tooltip>
<template #default="scope">
<slot :name="propItem.slotName" :row="scope.row">
{{ scope.row[propItem.prop] }}
</slot>
</template>
</el-table-column>
</template>
</el-table>
<div class="footer" v-if="showFooter">
<slot name="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page.currentPage"
:page-size="page.pageSize"
:page-sizes="[10, 20, 30]"
layout="total, sizes, prev, pager, next, jumper"
:total="listCount"
>
</el-pagination>
</slot>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
title: {
type: String,
default: ''
},
listData: {
type: Array,
required: true
},
listCount: {
type: Number,
default: 0
},
propList: {
type: Array,
required: true
},
showIndexColumn: {
type: Boolean,
default: false
},
showSelectColumn: {
type: Boolean,
default: false
},
page: {
type: Object,
default: () => ({ currentPage: 0, pageSize: 10 })
},
childrenProps: {
type: Object,
default: () => ({})
},
showFooter: {
type: Boolean,
default: true
}
},
emits: ['selectionChange', 'update:page'],
setup(props, { emit }) {
const handleSelectionChange = (value: any) => {
emit('selectionChange', value)
}
const handleCurrentChange = (currentPage: number) => {
emit('update:page', { ...props.page, currentPage })
}
const handleSizeChange = (pageSize: number) => {
emit('update:page', { ...props.page, pageSize })
}
return {
handleSelectionChange,
handleCurrentChange,
handleSizeChange
}
}
})
</script>
<style scoped lang="less">
.header {
display: flex;
height: 45px;
padding: 0 5px;
justify-content: space-between;
align-items: center;
.title {
font-size: 20px;
font-weight: 700;
}
.handler {
align-items: center;
}
}
.footer {
margin-top: 15px;
.el-pagination {
text-align: right;
}
}
</style>
page-content.vue
<template>
<div class="page-content">
<hy-table
:listData="dataList"
:listCount="dataCount"
v-bind="contentTableConfig"
v-model:page="pageInfo"
>
<!-- 1.header中的插槽 -->
<template #headerHandler>
<el-button
v-if="isCreate"
type="primary"
size="medium"
@click="handleNewClick"
>
新建用户
</el-button>
</template>
<!-- 2.列中的插槽 -->
<template #status="scope">
<el-button
plain
size="mini"
:type="scope.row.enable ? 'success' : 'danger'"
>
{{ scope.row.enable ? '启用' : '禁用' }}
</el-button>
</template>
<template #createAt="scope">
<span>{{ $filters.formatTime(scope.row.createAt) }}</span>
</template>
<template #updateAt="scope">
<span>{{ $filters.formatTime(scope.row.updateAt) }}</span>
</template>
<template #handler="scope">
<div class="handle-btns">
<el-button
v-if="isUpdate"
icon="el-icon-edit"
size="mini"
type="text"
@click="handleEditClick(scope.row)"
>
编辑
</el-button>
<el-button
v-if="isDelete"
icon="el-icon-delete"
size="mini"
type="text"
@click="handleDeleteClick(scope.row)"
>删除</el-button
>
</div>
</template>
<!-- 在page-content中动态插入剩余的插槽 -->
<template
v-for="item in otherPropSlots"
:key="item.prop"
#[item.slotName]="scope"
>
<template v-if="item.slotName">
<slot :name="item.slotName" :row="scope.row"></slot>
</template>
</template>
</hy-table>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, ref, watch } from 'vue'
import { useStore } from '@/store'
import { usePermission } from '@/hooks/use-permission'
import HyTable from '@/base-ui/table'
export default defineComponent({
components: {
HyTable
},
props: {
contentTableConfig: {
type: Object,
require: true
},
pageName: {
type: String,
required: true
}
},
emits: ['newBtnClick', 'editBtnClick'],
setup(props, { emit }) {
const store = useStore()
// 0.获取操作的权限
const isCreate = usePermission(props.pageName, 'create')
const isUpdate = usePermission(props.pageName, 'update')
const isDelete = usePermission(props.pageName, 'delete')
const isQuery = usePermission(props.pageName, 'query')
// 1.双向绑定pageInfo
const pageInfo = ref({ currentPage: 1, pageSize: 10 })
watch(pageInfo, () => getPageData())
// 2.发送网络请求
const getPageData = (queryInfo: any = {}) => {
if (!isQuery) return
store.dispatch('system/getPageListAction', {
pageName: props.pageName,
queryInfo: {
offset: (pageInfo.value.currentPage - 1) * pageInfo.value.pageSize,
size: pageInfo.value.pageSize,
...queryInfo
}
})
}
getPageData()
// 3.从vuex中获取数据
const dataList = computed(() =>
store.getters[`system/pageListData`](props.pageName)
)
const dataCount = computed(() =>
store.getters[`system/pageListCount`](props.pageName)
)
// 4.获取其他的动态插槽名称
const otherPropSlots = props.contentTableConfig?.propList.filter(
(item: any) => {
if (item.slotName === 'status') return false
if (item.slotName === 'createAt') return false
if (item.slotName === 'updateAt') return false
if (item.slotName === 'handler') return false
return true
}
)
// 5.删除/编辑/新建操作
const handleDeleteClick = (item: any) => {
console.log(item)
store.dispatch('system/deletePageDataAction', {
pageName: props.pageName,
id: item.id
})
}
const handleNewClick = () => {
emit('newBtnClick')
}
const handleEditClick = (item: any) => {
emit('editBtnClick', item)
}
return {
dataList,
getPageData,
dataCount,
pageInfo,
otherPropSlots,
isCreate,
isUpdate,
isDelete,
handleDeleteClick,
handleNewClick,
handleEditClick
}
}
})
</script>
<style scoped>
.page-content {
padding: 20px;
border-top: 20px solid #f5f5f5;
}
</style>
完事,开始用,首先有商品图片的列表怎么用呢?page-content里面使用插槽插入数据
<page-content :contentTableConfig="contentTableConfig" pageName="goods">
<template #image="scope">
<el-image
style="width: 60px; height: 60px"
:src="scope.row.imgUrl"
:preview-src-list="[scope.row.imgUrl]"
>
</el-image>
</template>
<template #oldPrice="scope">{{ '¥' + scope.row.oldPrice }}</template>
</page-content>
不需要有新的tabitem的就可以直接用了
<page-content
ref="pageContentRef"
:contentTableConfig="contentTableConfig"
pageName="users"
@newBtnClick="handleNewData"
@editBtnClick="handleEditData"
></page-content>
如果不明白的可以去github里面有所有代码,github项目地址https://github.com/lsh555/vue3-ems