Vue3 + Element 自定义数据表格组件 el-table
创建组件<script lang="ts">export default {name: "ReElTable"};</script><script setup lang="ts">import { getCurrentInstance, watch } from "vue";import { useI18n } from "vue-i18n";const { p
·
目录
1.0
创建组件
<script lang="ts">
export default {
name: "ReElTable"
};
</script>
<script setup lang="ts">
import { getCurrentInstance, watch } from "vue";
import { useI18n } from "vue-i18n";
const { proxy } = getCurrentInstance();
const { locale } = useI18n();
//监听国际化切换变化 用于国际化响应
watch(
() => locale.value,
() => {
//防止 进行国际化操作时 固定列出现 样式异常问题
proxy.$nextTick(() => {
proxy.$refs["filterTableRef"].doLayout();
});
}
);
//获取 父级传进的参数
const props = defineProps({
tableModule: {
type: Object,
default: null
}
});
</script>
<template>
<div>
<h1>使用组件</h1>
<el-table
ref="filterTableRef"
class="table-list"
row-key="date"
stripe
:data="props.tableModule.table.data"
v-loading="props.tableModule.table.loading"
@sort-change="props.tableModule.table.sortChangeFunc"
height="650"
:header-cell-style="{ background: '#f5f7fa' }"
>
<template v-for="(item, index) in props.tableModule.columns" :key="index">
<el-table-column
:prop="item.prop"
:width="item.width"
:min-width="item.minWidth"
:fixed="item.fixed"
:sortable="item.sortable"
:label="item.label"
:align="item.align"
:formatter="item.formatter"
:show-overflow-tooltip="item.showOverflowTooltip"
>
</el-table-column>
</template>
<template v-if="props.tableModule.operation">
<!-- 操作列-->
<el-table-column
align="center"
fixed="right"
:label="$t('table.operation')"
width="200"
>
<template #default="scope">
<template v-for="(item, index) in props.tableModule.operation" :key="index">
<template v-if="!item.popConfirm">
<!-- 普通按钮-->
<el-button
type="text"
size="small"
@click="item.clickFunc(scope.$index, scope.row)"
>{{ item.button }}</el-button
>
</template>
<template v-else>
<!-- 带有确认框的按钮-->
<el-popconfirm
:confirm-button-text="
!item.popConfirm.confirm
? $t('button.confirm')
: item.popConfirm.confirm
"
:cancel-button-text="
!item.popConfirm.cancel
? $t('button.cancel')
: item.popConfirm.cancel
"
:title="
!item.popConfirm.title
? $t('else.isDelete')
: item.popConfirm.title
"
@confirm="item.clickFunc(scope.row.id)"
>
<template #reference>
<el-button type="text" size="small">
{{ item.button }}
</el-button>
</template>
</el-popconfirm>
</template>
</template>
</template>
</el-table-column>
</template>
</el-table>
<!--分页-->
<el-pagination
:hide-on-single-page="false"
:current-page="props.tableModule.paging.currentPage"
:page-sizes="[5, 10, 15, 20, 25]"
:page-size="props.tableModule.paging.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="props.tableModule.paging.total"
@size-change="props.tableModule.paging.sizeChangeFunc"
@current-change="props.tableModule.paging.currentChangeFunc"
align="right"
></el-pagination>
</div>
</template>
<style scoped></style>
使用组件
ts
//引入组件 我的因为用的比较多所以 在main.js中引入了
import { ReElTable } from "/@/components/csms/re-el-table";
const tableModule = () => {
return {
table: {
data: state.tableData,
loading: state.tableLoading,
sortChangeFunc: onSortChange
},
columns: [
{ prop: "id", sortable: true, width: 120, label: t("table.id") },
{ prop: "stationName", label: t("table.name") },
{ prop: "state", label: t("table.state") }
],
operation: [
{ button: t("button.details"), clickFunc: onInfo },
{ button: t("button.delete"), popConfirm: true, clickFunc: onDel }
],
paging: {
currentPage: state.currentPage,
pageSize: state.pageSize,
total: state.total,
sizeChangeFunc: pageSizeChange,
currentChangeFunc: pageIndexChange
}
};
};
html
<ReElTable
:tableModule="tableModule"
>
</ReElTable>
效果:
这里修改了 删除按钮 只是为了做一个 示例
2.0--------优化多个操作项显示,优化删除确认框
优化
<script lang="ts">
export default {
name: "ReElTable"
};
</script>
<script setup lang="ts">
import { getCurrentInstance, watch, reactive } from "vue";
import { useI18n } from "vue-i18n";
const { proxy } = getCurrentInstance();
const { locale } = useI18n();
//监听国际化切换变化 用于国际化响应
watch(
() => locale.value,
() => {
//防止 进行国际化操作时 固定列出现 样式异常问题
proxy.$nextTick(() => {
proxy.$refs["filterTableRef"].doLayout();
});
}
);
//获取 父级传进的参数
const props = defineProps({
tableModule: {
type: Object,
default: null
}
});
//监听父级参数变化
watch(
() => props.tableModule,
() => {
handleOperation();
}
);
const operationArr = reactive([]);
const operationDropdownArr = reactive([]);
//用于对操作项显示处理
function handleOperation() {
if (!props.tableModule.operation) return;
operationArr.length = 0;
operationDropdownArr.length = 0;
let x = props.tableModule.operation.length > 3 ? 1 : 0;
props.tableModule.operation.forEach(arr => {
//判断是否显示
if (arr.permission != false) {
if (x < 3) {
operationArr.push(arr);
} else {
operationDropdownArr.push(arr);
}
x++;
}
});
}
handleOperation();
</script>
<template>
<div>
<el-table
ref="filterTableRef"
class="table-list"
size="large"
:row-key="props.tableModule.table.data?.id"
stripe
:data="props.tableModule.table.data"
v-loading="props.tableModule.table.loading"
@sort-change="props.tableModule.table.sortChangeFunc"
:max-height="
props.tableModule.table.height ? props.tableModule.table.height : 650
"
:header-cell-style="{ background: '#f5f7fa' }"
@selection-change="props.tableModule.table.selectionChange"
>
<template v-if="props.tableModule.table.selectionChange">
<el-table-column type="selection" width="55" />
</template>
<slot />
<template v-for="(item, index) in props.tableModule.columns" :key="index">
<el-table-column
:prop="item.prop"
:width="item.width"
:min-width="item.minWidth"
:fixed="item.fixed"
:sortable="item.sortable"
:label="item.label"
:align="item.align"
:formatter="item.formatter"
:show-overflow-tooltip="true"
/>
</template>
<template v-if="operationArr.length > 0">
<!-- 操作列-->
<el-table-column
align="center"
:fixed="props.tableModule.operationAttr?.fixed ?? 'right'"
:label="$t('title.operations')"
:width="props.tableModule.operationAttr?.width ?? 200"
>
<template #default="scope">
<template v-for="(item, index) in operationArr" :key="index">
<!-- 普通按钮-->
<el-button
type="primary"
link
size="small"
@click="item.clickFunc(scope.$index, scope.row)"
>{{ item.button }}</el-button
>
</template>
<el-dropdown
:hide-on-click="false"
v-if="operationDropdownArr.length > 0"
>
<el-button type="primary" size="small" link>
{{ $t("title.more") }}
<el-icon class="el-icon--right">
<IconifyIconOffline icon="arrow-down" />
</el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<template
v-for="(item, index) in operationDropdownArr"
:key="index"
>
<el-dropdown-item
:command="item.button"
@click="item.clickFunc(scope.$index, scope.row)"
>
{{ item.button }}
</el-dropdown-item>
</template>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</template>
</el-table>
<!--分页-->
<template v-if="props.tableModule.paging">
<el-pagination
:hide-on-single-page="false"
:current-page="props.tableModule.paging.currentPage"
:page-sizes="[5, 10, 20, 50, 100]"
:page-size="props.tableModule.paging.pageSize"
layout="->, total, sizes, prev, pager, next, jumper"
:total="props.tableModule.paging.total"
@size-change="props.tableModule.paging.sizeChangeFunc"
@current-change="props.tableModule.paging.currentChangeFunc"
/>
</template>
</div>
</template>
<style lang="scss" scoped>
//.el-button + .el-button {
// margin-left: 0 !important;
//}
</style>
优化:
1.不再使用弹出在按钮旁的询问框(没做防抖的话,快速点击会出现重复发送请求问题)
2.低于或包含三个操作项直接显示,超出则提供一个更多按钮,点击后显示其他操作项
弊端:
使用插槽不方便
2.1 ----------------支持插槽操作
支持插槽
ts
<script lang="ts">
export default {
name: "ReElTable"
};
</script>
<script setup lang="ts">
import { getCurrentInstance, watch, reactive } from "vue";
import { useI18n } from "vue-i18n";
const { proxy } = getCurrentInstance();
const { locale } = useI18n();
//监听国际化切换变化 用于国际化响应
watch(
() => locale.value,
() => {
//防止 进行国际化操作时 固定列出现 样式异常问题
proxy.$nextTick(() => {
proxy.$refs["filterTableRef"].doLayout();
});
}
);
//获取 父级传进的参数
const props = defineProps({
tableModule: {
type: Object,
default: null
}
});
//监听父级参数变化
watch(
() => props.tableModule,
() => {
handleOperation();
}
);
const operationArr = reactive([]);
const operationDropdownArr = reactive([]);
//用于对操作项显示处理
function handleOperation() {
if (!props.tableModule.operation) return;
operationArr.length = 0;
operationDropdownArr.length = 0;
let x = props.tableModule.operation.length > 3 ? 1 : 0;
props.tableModule.operation.forEach(arr => {
//判断是否显示
if (arr.permission != false) {
if (x < 3) {
operationArr.push(arr);
} else {
operationDropdownArr.push(arr);
}
x++;
}
});
}
handleOperation();
</script>
<template>
<div>
<el-table
ref="filterTableRef"
class="table-list"
size="large"
:row-key="props.tableModule.table.data?.id"
stripe
:data="props.tableModule.table.data"
v-loading="props.tableModule.table.loading"
@sort-change="props.tableModule.table.sortChangeFunc"
:max-height="
props.tableModule.table.height ? props.tableModule.table.height : 650
"
:header-cell-style="{ background: '#f5f7fa' }"
@selection-change="props.tableModule.table.selectionChange"
>
<!--多选框-->
<template v-if="props.tableModule.table.selectionChange">
<el-table-column type="selection" width="55" />
</template>
<template v-for="(item, index) in props.tableModule.columns" :key="index">
<!--是否为插槽-->
<template v-if="item.slotName">
<slot :name="item.slotName" />
</template>
<template v-else>
<!--列-->
<el-table-column
:prop="item.prop"
:width="item.width"
:min-width="item.minWidth"
:fixed="item.fixed"
:sortable="item.sortable"
:label="item.label"
:align="item.align"
:formatter="item.formatter"
:show-overflow-tooltip="true"
/>
</template>
</template>
<template v-if="operationArr.length > 0">
<!--操作列-->
<el-table-column
align="center"
:fixed="props.tableModule.operationAttr?.fixed ?? 'right'"
:label="$t('title.operations')"
:width="props.tableModule.operationAttr?.width ?? 200"
>
<template #default="scope">
<template v-for="(item, index) in operationArr" :key="index">
<!--普通按钮-->
<el-button
type="primary"
link
size="small"
@click="item.clickFunc(scope.$index, scope.row)"
>{{ item.button }}</el-button
>
</template>
<!--超出显示更多按钮-->
<el-dropdown
:hide-on-click="false"
v-if="operationDropdownArr.length > 0"
>
<el-button type="primary" size="small" link>
{{ $t("title.more") }}
<el-icon class="el-icon--right">
<IconifyIconOffline icon="arrow-down" />
</el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<template
v-for="(item, index) in operationDropdownArr"
:key="index"
>
<el-dropdown-item
:command="item.button"
@click="item.clickFunc(scope.$index, scope.row)"
>
{{ item.button }}
</el-dropdown-item>
</template>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</template>
</el-table>
<!--分页-->
<template v-if="props.tableModule.table.data">
<el-pagination
:hide-on-single-page="false"
:current-page="props.tableModule.paging.currentPage"
:page-sizes="[5, 10, 20, 50, 100]"
:page-size="props.tableModule.paging.pageSize"
layout="->, total, sizes, prev, pager, next, jumper"
:total="props.tableModule.paging.total"
@size-change="props.tableModule.paging.sizeChangeFunc"
@current-change="props.tableModule.paging.currentChangeFunc"
/>
</template>
</div>
</template>
<style lang="scss" scoped>
//.el-button + .el-button {
// margin-left: 0 !important;
//}
</style>
vue
模型
更多推荐
已为社区贡献2条内容
所有评论(0)