当将el-table进行封装,实现多个功能页面下都可以使用,为了使得页面的逻辑更加的清晰与灵活,将其分层。公共插槽放在公共组件中,功能页面独有的在各自的页面另外编写。实现跨组件插槽 name一致
el-table封装
主要对el-table进行封装
<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">
<slot name="footer">
<el-pagination
v-model:current-page="page.currentPage"
v-model:page-size="page.pageSize"
:page-sizes="[10, 20, 30]"
layout="total, sizes, prev, pager, next, jumper"
:total="totalCount"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</slot>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
export default defineComponent({
name: 'tableView',
props: {
title: {
type: String,
default: ''
},
listData: {
type: Array as PropType<any[]>,
default: () => []
},
propList: {
type: Array as PropType<any[]>,
default: () => []
},
childrenProps: {
type: Object,
default: () => ({})
},
showIndexColumn: {
type: Boolean,
required: false
},
showSelectColumn: {
type: Boolean,
required: false
},
totalCount: {
type: Number,
default: 0
},
page: {
type: Object,
default: () => ({
currentPage: 1,
pageSize: 10
})
}
},
emits: ['selectionChange', 'update:page'],
setup(props, { emit }) {
const handleSelectionChange = (value: any) => {
console.log('value', value)
emit('selectionChange', value)
}
const handleSizeChange = (currentPage: number) => {
emit('update:page', { ...props.page, currentPage })
}
const handleCurrentChange = (pageSize: number) => {
emit('update:page', { ...props.page, pageSize })
}
return {
handleSelectionChange,
handleSizeChange,
handleCurrentChange
}
}
})
</script>
page-content
主要对数据进行处理
<template>
<div class="page-content">
<hy-table
:listData="userList"
:listCount="dataCount"
v-model:page="pageInfo"
v-bind="contentTableConfig"
>
<!-- header中的插槽 -->
<template #headerHandler>
<el-button v-if="isCreate" type="primary" size="medium" @click="handleNewClick"
>新建用户</el-button
>
<el-button type="primary" size="medium">刷新</el-button>
</template>
<!-- 表格数据相关的插槽 -->
<!-- 公共插槽 -->
<template #status="scope">
<el-button plain size="mini" :type="scope.row.enable ? 'success' : 'danger'">{{
scope.row.enable ? '启用' : '禁用'
}}</el-button>
</template>
<template #createAt="scope">
<strong>{{ $filters.formatTime(scope.row.createAt) }}</strong>
</template>
<template #updateAt="scope">
<strong>{{ $filters.formatTime(scope.row.updateAt) }}</strong>
</template>
<template #handler="scope">
<div class="handle-btns">
<el-button v-if="isUpdate" size="mini" type="text" @click="handleEditClick(scope.row)"
>编辑</el-button
>
<el-button v-if="isDelete" size="mini" type="text" @click="handleDeleteClick(scope.row)"
>删除</el-button
>
</div>
</template>
<!-- 动态插槽内容 -->
<template v-for="item in otherPropSlots" :key="item.prop" #[item.slotName]="scope">
<template v-if="item.slotName">
<!-- 实现跨组件插槽 name一致 -->
<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 HyTable from '@/base-ui/table'
import { usePermission } from '@/hooks/use-permission'
export default defineComponent({
name: 'pageContent',
components: {
HyTable
},
props: {
contentTableConfig: {
type: Object,
required: true
},
pageName: {
type: String,
required: true
}
},
emits: ['newBtnClick', 'newEditClick'],
setup(props, { emit }) {
const store = useStore()
// store.dispatch('system/getPageListAction', {
// pageUrl: '/user/list',
// queryInfo: {
// offset: 0,
// size: 10
// }
// })
// const userList = computed(() => store.state.system.userList)
// const userCount = computed(() => store.state.system.userCount)
// 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')
// 分页器相关数据(双向绑定的pageInfo)
const pageInfo = ref({ currentPage: 1, pageSize: 10 })
// 监听翻页/切换size,改变则重新调接口
watch(pageInfo, () => getPageData())
/**
* 不同的菜单页面、根据传入的分页数据去获取对应的数据
*/
const getPageData = (queryInfo: any = {}) => {
// 沒有权限就不发请求
if (!isQuery) return
store.dispatch('system/getPageListAction', {
pageName: props.pageName,
queryInfo: {
offset: pageInfo.value.currentPage,
size: pageInfo.value.pageSize,
...queryInfo
}
})
}
getPageData() // 也可以使用watchEffect,自动执行一次
// 从vuex中获取数据
const userList = computed(() => store.getters[`system/pageListData`](props.pageName))
const dataCount = computed(() => store.getters[`system/pageListCount`](props.pageName))
/***
* 公共的插槽可以放在pageContent页面
* 动态插槽[各个页面独有的插槽]在这个地方先分析出来,然后在pageContent也使用插槽实现跨组件插槽
*/
// 获取其他的动态插槽名称
const conSlots = ['status', 'createAt', 'updateAt', 'handler'] // 公共插槽
// 动态插槽:根据不同的功能展示对应的内容
const otherPropSlots = props.contentTableConfig?.propList.filter((item: any) => {
if (conSlots.indexOf(item.slotName) !== -1) return false
return true
})
// 5.删除
const handleDeleteClick = (item: any) => {
store.dispatch('system/deletePageDataAction', {
pageName: props.pageName,
id: item.id
})
}
const handleNewClick = () => {
emit('newBtnClick')
}
const handleEditClick = (item: any) => {
emit('newEditClick', item)
}
return {
userList,
getPageData,
dataCount,
pageInfo,
otherPropSlots,
isCreate,
isUpdate,
isDelete,
handleDeleteClick,
handleNewClick,
handleEditClick
}
}
})
</script>
功能页面
只需要传入配置数据
<template>
<div class="goods">
<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>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import pageContent from '@/components/page-content/src/page-content.vue'
import { contentTableConfig } from './config/content.config'
export default defineComponent({
name: 'goodsView',
components: {
pageContent
},
setup() {
return {
contentTableConfig
}
}
})
</script>
<style lang="scss" scoped></style>
// 配置数据
export const contentTableConfig = {
title: '商品列表',
propList: [
{ prop: 'name', label: '商品名称', minWidth: '80' },
{ prop: 'oldPrice', label: '原价格', minWidth: '80', slotName: 'oldPrice' },
{ prop: 'newPrice', label: '现价格', minWidth: '80' },
{ prop: 'imgUrl', label: '商品图片', minWidth: '100', slotName: 'image' },
{ prop: 'status', label: '状态', minWidth: '100', slotName: 'status' },
{ prop: 'createAt', label: '创建时间', minWidth: '250', slotName: 'createAt' },
{ prop: 'updateAt', label: '更新时间', minWidth: '250', slotName: 'updateAt' },
{
lable: '操作',
minWidth: '120',
slotName: 'handler'
}
],
showIndexColumn: true, // 显示序列行
showSelectColumn: true // 显示多选
}
动态插槽写法
学习笔记,版权归coderWhy