简介: 基于 vue3 + el-table 封装的通用表格组件 的 tsx写法,想要参考模板写法的可以到我另一篇博客喔~
TS + vue3.2 + vite2 + element-plus 通用表格组件封装
话不多说,本组件分为四部分:
1、CommonTable.module.scss 文件为组件样式文件
:global {
.common-table {
.el-table__header,
.el-table__body {
margin: 0;
}
.el-table::before {
height: 0;
}
.el-button {
padding: 0;
border: none;
margin: 0 4px;
padding: 0 4px 0 8px;
border-left: 1px solid #e2e2e2;
font-size: 14px;
min-height: 14px;
&:first-child {
border-left: none;
}
}
.el-button+.el-button {
margin-left: 0;
}
.btn-right div {
margin-right: 5px;
}
.btn-right div:empty {
margin-right: 0px;
}
//斑马纹表格背景色
.el-table .even-row {
--el-table-tr-background-color: #f5fafb;
}
.el-table .odd-row {
--el-table-tr-background-color: #ffffff;
}
.el-table--border::after,
.el-table--group::after {
width: 0;
}
.el-table__fixed-right::before,
.el-table__fixed::before {
background-color: transparent;
}
.custom-table-header {
th {
background-color: #fff4d9 !important;
}
}
.progress-line {
.el-progress-bar__outer {
height: 16px !important;
}
.el-progress-bar__outer,
.el-progress-bar__inner {
border-radius: 0 !important;
}
}
.text-no-wrap {
cursor: pointer;
display: inline;
}
.el-table {
td.el-table__cell div,
th.el-table__cell>.cell {
font-size: 14px;
}
th.el-table__cell>.cell {
font-weight: normal;
}
.cell {
padding: 0 10px;
line-height: 39px;
}
.el-table__header-wrapper .checkBoxRadio .el-checkbox {
display: none;
}
.el-checkbox {
display: flex;
align-items: center;
justify-content: center;
}
.table-img {
width: 60px;
height: 60px;
object-fit: cover;
padding: 6px 0;
display: flex;
align-items: center;
margin: 0 auto;
justify-content: center;
}
}
.el-table--small .el-table__cell {
padding: 0;
}
.el-dropdown-menu__item {
padding: 5px 10px !important;
.el-button {
width: 100%;
text-align: center;
padding: 0 8px;
margin: 0;
}
}
.flex-box {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
.item {
margin: 0 10px;
}
}
}
}
2、CommonTable.module.ts为组件逻辑文件
import {
ref,
watch,
nextTick
} from 'vue';
export default function(props, emit, CommonTable) {
const curPageCheck = ref([])
watch(() => props.data, () => {
if (props.showCheckBox || props.turnRadio) {
nextTick(() => {
CommonTable.value.clearSelection()
curPageCheck.value = []
if (props.showCheckBox && props.turnRadio) {
props.data.filter((item) => {
if (item.id === props.selectedIdArr[0]) {
CommonTable.value.toggleRowSelection(item, true)
}
})
} else if (props.showCheckBox) {
props.data.filter((item) => {
if (props.selectedIdArr.includes(item.id)) {
CommonTable.value.toggleRowSelection(item, true)
curPageCheck.value.push(item.id)
}
})
}
})
}
}, {
immediate: true
})
watch(() => props.selectedIdArr, (val) => {
if (props.showCheckBox || props.turnRadio) {
nextTick(() => {
CommonTable.value.clearSelection()
curPageCheck.value = []
if (props.showCheckBox && props.turnRadio) {
props.data.filter((item) => {
if (item.id === val[0]) {
CommonTable.value.toggleRowSelection(item, true)
}
})
} else if (props.showCheckBox) {
props.data.filter((item) => {
if (val.includes(item.id)) {
CommonTable.value.toggleRowSelection(item, true)
curPageCheck.value.push(item.id)
}
})
}
})
}
}, {
immediate: true
})
const methods = {
/**
* prop 单值 或者 数组过滤(此处为针对时间组,不作为通用处理)
*/
propFilter(prop, row) {
const res = prop.reduce((total, cur) => {
if (row[cur]) {
return (total += row[cur] + '~')
} else {
return ''
}
}, '')
return res ? res.replace(/~$/, '') : ''
},
handleTableButton(row, type) {
if (!type) return;
emit('operation', row, type);
},
/**
* 后续扩展位
* @param {*} methods
* @param {*} row
*/
handleClickon(methods, row) {
if (!methods) return;
emit(methods, { methods, row })
},
handleSelectionChange(val) {
if (props.showCheckBox && props.turnRadio) {
// 选择项大于1时
if (val.length > 1) {
const del_row = val.shift()
CommonTable.value.toggleRowSelection(del_row, false)
}
}
// 全选
if (props.showCheckBox && props.selectedIdArr) {
if (props.turnRadio) {
emit('handle-selection-change', val)
} else {
// 一般复选框都是走到这一步
emit('handle-selection-change', val)
}
} else {
emit('handle-selection-change', val)
}
},
getRowKeys(row) {
return row.id
},
selectAll(val) {
if (props.showCheckBox && props.turnRadio) {
// 选择项大于1时
if (val.length > 1) {
val.length = 1
}
}
emit('handle-selection-change', val)
},
// 斑马纹表格背景色
tabRowClassName({ rowIndex }) {
const classList = []
// 默认样式配置
const index = rowIndex + 1;
if (index % 2 === 0) {
classList.push('even-row');
} else {
classList.push('odd-row');
}
// 自定义样式配置
classList.push(this.rowClassName({ row, rowIndex }))
return classList.join(' ');
},
cellClassName({ row, columnIndex }) {
if (row.confirmTag === 2 && columnIndex < props.tableLabel.length) {
return 'height_light_cell'
} else {
return ''
}
},
buttonDisabled(item, row) {
if (typeof item.disabled === 'function') return item.disabled(row) || false
if (!item.disabled) return item.disabled
},
/**
* 单选框选中事件
*/
rowClick(row) {
emit('rowClick', row)
}
}
return {
methods
}
}
3、CommonTable.tsx为组件渲染文件
import {
defineComponent,
ref,
PropType
} from 'vue';
import {
TableLabel,
TableDataItem
} from './types';
import useModule from './CommonTable.module';
import './CommonTable.module.scss';
export default defineComponent({
name: 'CommonTable',
props: {
/**
* 表格最高高度
*/
maxHeight: {
type: [String, Number],
default: 'auto'
},
/**
* 表格自定义属性展示
*/
tableLabel: {
type: Array as PropType<TableLabel[]>,
default: () => []
},
/**
* 表格数据源
*/
data: {
type: Array as PropType<TableDataItem[]>,
default: () => []
},
/**
* 配置需要显示的操作菜单
*/
option: {
type: Object,
default: () => {}
},
showCheckBox: {
// 配置是否显示全选(复选框)
type: Boolean,
default: false
},
/**
* 是否显示索引
*/
showIndex: {
type: Boolean,
default: false
},
turnRadio: {
type: Boolean,
default: false
},
selectedIdArr: {
type: Array as PropType<number[] | string[]>,
default: () => []
},
/**
* 是否 隐藏文字过长
*/
overflowText: {
type: Boolean,
default: false
},
/**
* 加载提示
*/
loading: {
type: Boolean,
default: false
},
/**
* 是否保持之前复选框的数据
*/
keep: {
type: Boolean,
default: false
},
/**
* 动态绑定 key 值
*/
keyId: {
type: String,
default: 'id'
},
/**
* 行内自定义样式配置
*/
rowStyle: {
type: Object,
default: () => {
return {
height: '40px'
}
}
},
/**
* 是否展示展开按钮
*/
showExpand: {
type: Boolean,
default: false
},
/**
* 行内自定义class
*/
rowClassName: {
type: Function,
default: () => {
return () => {}
}
}
},
setup(props, { emit, slots }) {
const CommonTable = ref(null)
const {
methods
} = useModule(props, emit, CommonTable)
return () => (
<div v-loading={props.loading}>
<el-table
class='common-table'
ref={CommonTable}
data={props.data}
border
max-height={props.maxHeight}
row-class-name={methods.tabRowClassName}
row-style={props.rowStyle}
cell-class-name={methods.cellClassName}
header-row-class-name='custom-table-header'
row-key={props.keyId}
on-select={methods.handleSelectionChange}
on-select-all={methods.handleSelectionChange}
>
{
props.showCheckBox && <el-table-column
key='showCheckBox'
width='55'
type='selection'
reserve-selection={props.keep}
class-name={props.turnRadio ? 'checkBoxRadio' : ''}
align='center'
/>
}
{
props.showExpand && <el-table-column
key='showExpand'
type='expand'
scopedSlots={{
default: scope => {
return <fragment row={scope.row}>
{
slots.expand?.()
}
</fragment>
}
}}
>
</el-table-column>
}
{
props.showIndex && <el-table-column
align='center'
label='序号'
width='50'
scopedSlots={{
default: scope => {
return scope.$index + 1
}
}}
>
</el-table-column>
}
{
props.tableLabel.map((item: TableLabel) => {
return <el-table-column
key={item[props.keyId]}
width={item.width ?? ''}
align={item.align ?? 'center'}
label={item.label}
show-overflow-tooltip={props.overflowText}
fixed={item.fixed}
prop={item.prop}
scopedSlots={{
default: (scope) => {
if (item.render) {
return <div
style='cursor: pointer'
onClick={() => item.methods && methods.handleClickon(item.methods, scope.row)}
domPropsInnerHTML={item.render(scope.row)}
>
</div>
} else {
return <div
class='text-no-wrap'
onClick={() => item.methods && methods.handleClickon(item.methods, scope.row)}>
{
Object.prototype.toString.call(item.prop) === '[object Array]' ? methods.propFilter(item.prop, scope.row) : (scope.row[item.prop] ?? '--')
}
</div>
}
}
}}
>
</el-table-column>
})
}
{
props.option && <el-table-column
width={props.option.width}
label={props.option.label}
fixed={props.option.fixed}
align={props.option.align ?? 'center'}
scopedSlots={{
default: scope => {
return props.option.children.length && <div
class='flex-box'
>
{
props.option.children.map(item => {
return <el-tooltip
class='item'
effect='light'
popper-class='item.popperClass || 'default-tooltip-primary''
content={item.label}
placement='top'
>
<i
class={['default-tooltip-icon', item.icon]}
plain='true'
onClick={() => methods.handleTableButton(scope.row, item.methods)}
/>
</el-tooltip>
})
}
</div>
}
}}
>
</el-table-column>
}
</el-table>
</div>
)
}
})
4、types.ts为类型定义文件
/** 表格行数据类型 */
export interface TableDataItem {
xxx: number;
}
/** 表格基础类型配置 */
interface BasicLabel {
label: string; // 标题
width?: number | string; // 宽度
fixed?: string; // 固定位置
align?: string; // 行排列
visible?: boolean; // 是否展示
}
/** 表格顶部类型配置 */
export interface TableLabel extends BasicLabel {
prop: string;
methods?: string;
render?: render;
mode?: string;
selects?: Select[]
}
/** 表格顶部自定义函数类型 */
interface render {
(row: TableDataItem): string
}
/** 表格操作栏类型 */
export interface OptionLabel extends BasicLabel {
prop?: string;
children: OptionChild[]
}
/** 表格操作栏子选项类型 */
export interface OptionChild {
label: string; // 标题
icon: string; // icon图标
method: string; // 执行方法
permission: string | string[]; // 权限
}
5、组件调用方式
组件调用:
<CommonTable
show-index
show-check-box={true}
loading={loading.value}
max-height={550}
table-label={tableHeaderData}
data={tableData.value}
option={tableOptionsData}
on-operation={methods.operationHandler}
on-handle-selection-change={methods.handleSelectionChange}
/>
属性及方法使用说明:
注意:如果你在使用Sortable插件想要拖动排序表格时,tableOptionsData 下的fixed参数请不要写,不然会导致无法拖动!文章来源:https://www.toymoban.com/news/detail-606439.html
/** 表格头部配置 */
const tableHeaderData = [
{
label: '文件大小',
prop: 'size',
width: '100',
render(row) {
return xxx
}
}
]
/** 表格操作栏配置 */
const tableOptionsData = {
label: '操作',
width: '150',
fixed: 'right',
children: [
{
label: '操作记录',
icon: 'xxx',
methods: 'record',
permission: ''
}
]
}
const methods = {
/**
* 操作栏分发逻辑
* @param row 当行数据
* @param type 分发函数名
*/
operationHandler(row: TableDataItem, type: string) {
if (type === 'record') { // 操作记录
}
},
/**
* 复选框处理回调
* @param val 复选框选中的数据
*/
handleSelectionChange(val: TableDataItem[]) {
multipleSelection.value = val
}
}
有不懂的可以底下评论噢~文章来源地址https://www.toymoban.com/news/detail-606439.html
到了这里,关于【TSX】vue3 + element-ui + tsx 通用表格组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!