封装el-table组件,在网上搜了些,都是要把事件重写一遍,发现vue3不支持listeners了合并到attrs内了,于是有了一个简单的思路
将attrs内的on开头的事件重新赋值给一个对象然后用v-on绑定到组件上
<script setup>
import { computed, ref, useAttrs } from 'vue'
import { ElTable } from 'element-plus'
const attrs = useAttrs()
// 取on开头的属性,给e-table添加v-on绑定事件,并在attrs删除
let onMethods = {}
let removeMethods = {}
for (let key in attrs) {
if (key.startsWith('on')) {
onMethods[key.replace('on', '')] = attrs[key]
removeMethods[key] = undefined
}
}
const props = defineProps({
tableData: Array,
columns: Array,
options: [Object, null]
})
const tableRef = ref()
// 设置option默认值,如果传入自定义的配置则合并option配置项
const _options = computed(() => {
const option = {
// size: "small",
stripe: false,
tooltipEffect: 'dark',
showHeader: true,
showPagination: false,
rowStyle: () => 'cursor:pointer' // 行样式
}
return Object.assign(option, attrs, removeMethods)
})
// 合并分页配置
const _paginationConfig = computed(() => {
const config = {
total: 0,
currentPage: 1,
pageSize: 10,
pageSizes: [10, 20, 30, 40, 50, 100],
layout: 'total, sizes, prev, pager, next, jumper'
}
return Object.assign(config, props.options?.paginationConfig || {})
})
const emit = defineEmits([
'size-change', // pageSize事件
'current-change', // currentPage按钮组事件
'pagination-change', // currentPage或者pageSize改变触发
])
// 自定义索引
const indexMethod = (index) => {
const tabIndex = index + (_paginationConfig.value.currentPage - 1) * _paginationConfig.value.pageSize + 1
return tabIndex
}
// 切换pageSize
const pageSizeChange = (pageSize) => {
emit('size-change', pageSize)
emit('pagination-change', 1, pageSize)
}
// 切换currentPage
const currentPageChange = (currentPage) => {
emit('current-change', currentPage)
emit('pagination-change', currentPage, _paginationConfig.value.pageSize)
}
// 暴露给父组件参数和方法,如果外部需要更多的参数或者方法,都可以从这里暴露出去。
defineExpose({ element: tableRef })
</script>
<template>
<div>
<!--v-on绑定事件 v-bind绑定参数-->
<el-table ref="tableRef" :data="tableData" v-bind="_options" v-on="onMethods">
<template v-for="(col, index) in columns" :key="index">
<!---复选框, 序号 (START)-->
<el-table-column v-if="col.type === 'index' || col.type === 'selection' || col.type === 'expand'" :index="indexMethod" v-bind="col">
<!-- 当type等于expand时, 配置通过h函数渲染、txs语法或者插槽自定义内容 -->
<template #default="{ row, $index }">
<!-- render函数 (START) : 使用内置的component组件可以支持h函数渲染和txs语法 -->
<component v-if="col.render" :is="col.render" :row="row" :index="$index" />
<!-- render函数 (END) -->
<!-- 自定义slot (START) -->
<slot v-else-if="col.slot" name="expand" :row="row" :index="$index"></slot>
<!-- 自定义slot (END) -->
</template>
</el-table-column>
<!---复选框, 序号 (END)-->
<!-- 渲染插槽 START -->
<slot v-else-if="col.slot" :name="col.slot"></slot>
<el-table-column v-else v-bind="col"></el-table-column>
<!-- 渲染插槽 END -->
</template>
</el-table>
<!-- 分页器 -->
<div v-if="_options.showPagination" class="fx fx_ai_c fx_jc_e" style="width: 100%;margin-top: 5px;">
<el-pagination v-bind="_paginationConfig" @size-change="pageSizeChange" @current-change="currentPageChange" />
</div>
</div>
</template>
<style lang="scss" scoped>
:deep(.el-image__inner) {
transition: all 0.3s;
cursor: pointer;
&:hover {
transform: scale(1.2);
}
}
.mt20 {
margin-top: 20px;
}
</style>