前言
表格对于管理类项目是很重要的,可以只管的展示和比比较数据。使用Element Plus
能解决一部分问题,但是还存在一些缺点和不足。
分析
-
浏览器上表格数据展示空间不足。 -
列显示太多不够直观。 -
完全依赖官方表格组件代码过于臃肿不利于管理和优化。
实现
根据以上分析我们做出了如下解决方案
-
我们将表格组件分为两区域,操作区域和表格区域。
<template>
<el-card class="ve-table" shadow="never">
<template #header>
<div class="card-header">
<el-space size="small">
<el-icon style="font-size: 20px">
<CarbonTableShortcut/>
</el-icon>
<span>{{ $t('root.tableDataArea') }}</span>
</el-space>
<div>
<slot name="header"/>
</div>
</div>
</template>
<slot name="main"/>
</el-card>
</template>
-
表格区我们依据 Element Plus
提供的表格组件再进一步封装。 -
解决表格再浏览器上展示数据空间不足的问题,我们提出了表格全屏的解决方案。 -
解决列显示太多不够直观的问题,我们提出了列显隐的解决方案。 -
想要还原表格效果我们做了一个刷新表格的功能。
<template>
<el-table-column v-if="expand" type="expand" fixed>
<template #default="scope">
<slot name="expand" :row="scope.row"/>
</template>
</el-table-column>
<el-table-column
v-if="selection"
fixed
type="selection"/>
<el-table-column
v-if="index"
fixed
type="index"/>
<template v-for="(item, index) of columnList"
:key="index">
<el-table-column
v-if="hasColumn(item.prop)"
:sortable="item.sortable"
:prop="item.prop"
:fixed="item.fixed"
:min-width="item.minWidth"
:label="item.label">
<template v-if="item.coverColumn" #default="scope">
<slot :name="item.prop" :row="scope.row"/>
</template>
</el-table-column>
</template>
<el-table-column
v-if="operationShow"
:width="operationWidth"
fixed="right">
<template #header>
<label>{{ $t('root.operation') }}</label>
<div class="operation-colum">
<el-tooltip
effect="dark"
:content="tableFullScreen?$t('button.exitFullScreen'):$t('button.fullScreen')"
placement="bottom-end">
<el-link
:underline="false"
type="primary"
:icon="tableFullScreen? RiFullscreenExitLine:RiFullscreenFill"
@click="handleFullScreen"/>
</el-tooltip>
<el-tooltip
effect="dark"
:content="$t('button.refresh')"
placement="bottom-end">
<el-link
:underline="false"
type="primary"
:icon="Refresh"
@click="handleRefresh"/>
</el-tooltip>
<el-popover
placement="bottom-end"
:title="$t('button.columnSetting')"
width="200px"
trigger="hover">
<template #reference>
<el-link
:underline="false"
type="primary"
:icon="Tools">
</el-link>
</template>
<el-checkbox
class="ve-column-checkbox"
v-model="checkAll"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange">{{ $t('button.checkAll') }}
</el-checkbox>
<div class="scrollbar">
<el-checkbox-group v-model="checkedColumn" @change="handleCheckedColumnChange">
<el-checkbox
class="ve-column-checkbox"
v-for="(item, index) of columnList"
:key="index"
:label="item.prop">
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
</div>
</el-popover>
</div>
</template>
<template #default="scope">
<slot name="default" :row="scope.row"/>
</template>
</el-table-column>
</template>
const props = defineProps({
operationShow: {
type: Boolean,
required: false,
default: () => true
},
operationWidth: {
type: String,
required: false,
default: () => '262px'
},
expand: {
type: Boolean,
required: false,
default: () => false
},
selection: {
type: Boolean,
required: false,
default: () => false
},
index: {
type: Boolean,
required: false,
default: () => false
},
columnList: {
type: Array as () => Array<any>,
required: true,
default: () => []
}
})
const checkAll = ref(true)
const isIndeterminate = ref(false)
const column = props.columnList.map(item => {
return item.prop
})
const checkedColumn = ref(props.columnList.map(item => {
if (!item.columnSetting) {
return item.prop
}
}))
const handleCheckAllChange = (val: boolean) => {
checkedColumn.value = val ? column : []
isIndeterminate.value = false
}
const handleCheckedColumnChange = (value: string[]) => {
const checkedCount = value.length
checkAll.value = checkedCount === column.length
isIndeterminate.value = checkedCount > 0 && checkedCount < column.length
}
const hasColumn = (item) => {
return checkedColumn.value.includes(item)
}
const handleRefresh = () => {
emitter.emit('refresh')
}
const tableFullScreen = ref(false)
const handleFullScreen = () => {
if (!tableFullScreen.value) {
document.getElementsByClassName('ve-table')[0].classList.add('ve-tableFullScreen')
const barHeight = document.getElementsByClassName('ve-table')[0].getElementsByClassName('el-card__header')[0].clientHeight
tableHeight.value = document.body.clientHeight - barHeight - 78
} else {
document.getElementsByClassName('ve-table')[0].classList.remove('ve-tableFullScreen')
getTableHeight()
}
tableFullScreen.value = !tableFullScreen.value
}
例子
<template>
<TableArea>
<template #header>
<el-button
v-if="$route.meta.hasBtnPermission.includes('inviteToJoin')"
type="primary"
:icon="Share"
@click="handleClick('inviteToJoin')">
{{ $t('button.inviteToJoin') }}
</el-button>
<el-button
v-if="$route.meta.hasBtnPermission.includes('add')"
type="primary"
:icon="CirclePlus"
@click="handleClick('add')">
{{ $t('button.add') }}
</el-button>
<el-button
v-if="$route.meta.hasBtnPermission.includes('batchDelete')"
type="danger"
plain
:icon="Delete"
@click="handleClick('batchDelete')">
{{ $t('button.batchDelete') }}
</el-button>
<el-button
v-if="$route.meta.hasBtnPermission.includes('export')"
type="primary"
plain
:icon="Download"
@click="handleClick('export')">
{{ $t('button.export') }}
</el-button>
</template>
<template #main>
<el-table v-loading="props.loading"
:data="props.tableData"
border
:default-sort="{ prop: 'createTime', order: 'ascending' }"
@selection-change="onSelectionChange"
:height="tableHeight">
<TableColumn :columnList="columnList" :selection="true" :index="false">
<template #isDisableCh="scope">
<el-switch
v-model="scope.row.isDisable"
inline-prompt
:active-value="false"
:inactive-value="true"
:active-text="$t('button.enable')"
:inactive-text="$t('button.disabled')"
@change="handleClick('changeDisable', scope.row)"
/>
</template>
<template #default="scope">
<el-button
v-if="$route.meta.hasBtnPermission.includes('details')"
plain
size="small"
:icon="Document"
@click="handleClick('details', scope.row.id)">
{{ $t('button.details') }}
</el-button>
<el-button
v-if="$route.meta.hasBtnPermission.includes('edit')"
plain
type="primary"
size="small"
:icon="Edit"
@click="handleClick('edit', scope.row.id)">
{{ $t('button.edit') }}
</el-button>
<el-button
v-if="$route.meta.hasBtnPermission.includes('delete')"
plain
type="danger"
size="small"
:icon="Delete"
@click="handleClick('delete', scope.row.id)">
{{ $t('button.delete') }}
</el-button>
</template>
</TableColumn>
</el-table>
<slot name="pagination"/>
</template>
</TableArea>
</template>
const props = defineProps({
loading: {
type: Boolean,
required: true,
default: () => false
},
tableData: {
type: Array as () => Array<UserInfoPageVo>,
required: true,
default: () => []
}
})
const columnList = computed(() => [
{
fixed: true,
sortable: true,
prop: 'username',
minWidth: '130',
label: t('user.username')
},
{
sortable: true,
prop: 'nickname',
minWidth: '120',
label: t('user.nickname')
},
{
sortable: true,
prop: 'mobile',
minWidth: '120',
label: t('user.mobile')
},
{
sortable: true,
prop: 'createTime',
minWidth: '160',
label: t('user.creationTime')
},
{
sortable: true,
prop: 'isDisableCh',
minWidth: '100',
coverColumn: true,
label: t('user.isDisable')
}
])
const selected = ref<Array<UserInfoPageVo>>([])
const onSelectionChange = (val: UserInfoPageVo[]) => {
selected.value = val
}
const emits = defineEmits(['onTableClick'])
const handleClick = (type, id) => {
if (type === 'batchDelete') {
if (selected.value.length === 0) {
ElMessage.warning(t('message.selectDelete'))
return
}
let idArray = []
selected.value.forEach(row => idArray.push(row.id))
id = idArray.join(',')
}
emits('onTableClick', type, id)
}
原文始发于微信公众号(刘凌枫羽工作室):基于Vue+Element Plus实现表格组件
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/251408.html