elementui-table 表格二次封装(含 搜索工具、表格列表、页码),适用不太复杂场景
前言:1.使用具名插槽动态插入表格顶部检索框,使用具名插槽动态插入表格列数据;页码封装成单独组件。
2.本代码中有简单适配手机端的部分,不使用可以去除。
步骤1.在src=>components=>DataTable
DataTable:
<template>
<div class="app-container">
<!-- 过滤搜索 -->
<div class="filter-container">
<!--用插槽留好位置,使用该table组件可以动态插入元素 -->
<slot name="filter-content" />
<el-row>
<el-col>
<el-button v-if="options.addRoute" type="primary" icon="el-icon-plus" @click="handleAdd">添加</el-button>
</el-col>
</el-row>
</div>
<!-- 批量操作按钮 -->
<div v-show="multiShow && options.multiActions" class="filter-container">
<el-select v-model="multiNow" :placeholder="selectedLabel" class="filter-item" style="width: 130px"
@change="handleOption">
<el-option v-for="item in options.multiActions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<!-- 表格 -->
<el-table v-loading="listLoading" :data="dataList.records" border fit highlight-current-row
:header-cell-style="{ 'background': '#f2f3f4', 'color': '#555', 'font-weight': 'bold', 'line-height': '32px' }"
@selection-change="handleSelection">
<el-table-column v-if="options.multi" align="center" type="selection" width="55" />
<!--用插槽留好位置,使用该table组件可以动态插入元素 -->
<slot name="data-columns" />
</el-table>
<!-- 页码 ,封装成单独组件-->
<pagination v-show="dataList.total > 0" :total="dataList.total" :page.sync="listQuery.current"
:limit.sync="listQuery.size" @pagination="getList" />
</div>
</template>
<script>
import { fetchList, deleteData, changeState } from '@/api/common'
import Pagination from '@/components/Pagination'
export default {
name: 'PagingTable',
components: { Pagination },
// 组件入参
props: {
options: {
type: Object,
default: () => {
return {
// 批量操作
multiActions: [],
// 列表请求URL
listUrl: '/exam/api',
// 删除请求URL
deleteUrl: '',
// 启用禁用
stateUrl: '',
// 可批量操作
multi: false
}
}
},
// 列表查询参数
listQuery: {
type: Object,
default: () => {
return {
current: 1,
size: 10,
params: {},
t: 0
}
}
}
},
data() {
return {
// 接口数据返回
dataList: {
total: 0
},
// 数据加载标识
listLoading: true,
// 选定和批量操作
selectedIds: [],
selectedObjs: [],
// 显示已中多少项
selectedLabel: '',
// 显示批量操作
multiShow: false,
// 批量操作的标识
multiNow: ''
}
},
watch: {
// 检测查询变化
listQuery: {
handler() {
this.getList()
},
deep: true
}
},
created() {
this.getList()
},
methods: {
/**
* 添加数据跳转
*/
handleAdd() {
if (this.options.addRoute) {
this.$router.push({ name: this.options.addRoute, params: {} })
return
}
console.log('未设置添加数据跳转路由!')
},
/**
* 查询数据列表
*/
getList() {
this.listLoading = true
this.listQuery.t = new Date().getTime()
fetchList(this.options.listUrl, this.listQuery)
.then(response => {
this.dataList = response.data
this.$emit('getData', this.dataList.records)
this.listLoading = false
})
.catch(() => {
this.listLoading = false
})
},
/**
* 搜索
*/
handleFilter() {
// 重新搜索
this.getList()
},
/**
* 批量操作回调
*/
handleOption(v) {
this.multiNow = ''
// 内部消化的操作
if (v === 'delete') {
this.handleDelete()
return
}
if (v === 'enable') {
this.handleState(0)
return
}
if (v === 'disable') {
this.handleState(1)
return
}
// 向外回调的操作
this.$emit('multi-actions', { opt: v, ids: this.selectedIds })
},
/**
* 修改状态,启用禁用
*/
handleState(state) {
// 修改状态
changeState(this.options.stateUrl, this.selectedIds, state).then(response => {
if (response.code === 0) {
this.$message({
type: 'success',
message: '状态修改成功!'
})
// 重新搜索
this.getList()
}
})
},
/**
* 删除数据
*/
handleDelete() {
if (this.selectedIds.length === 0) {
this.$message({
message: '请至少选择一条数据!',
type: 'warning'
})
return
}
// 删除
this.$confirm('确实要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteData(this.options.deleteUrl, this.selectedIds).then(() => {
this.$message({
type: 'success',
message: '删除成功!'
})
this.getList()
})
})
},
/**
* 列表多选操作
* @param val
*/
handleSelection(val) {
const ids = []
val.forEach(row => {
ids.push(row.id)
})
this.selectedObjs = val
this.selectedIds = ids
this.multiShow = ids.length > 0
this.selectedLabel = '已选' + ids.length + '项'
this.$emit('select-changed', { ids: this.selectedIds, objs: this.selectedObjs })
}
}
}
</script>
<style>
.filter-container .filter-item {
margin-left: 5px;
}
.filter-container .filter-item:first-child {
margin-left: 0px;
}
</style>
步骤2,使用DataTable组件:
<template>
<data-table
ref="pagingTable"
:options="options"
:list-query="listQuery"
>
<template slot="filter-content">
<el-select v-model="listQuery.params.openType" class="filter-item" placeholder="开放类型" clearable>
<el-option
v-for="item in openTypes"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="listQuery.params.startTime"
class="filter-item"
value-format="yyyy-MM-dd"
type="date"
placeholder="考试开始时间"
/>
<el-date-picker
v-model="listQuery.params.endTime"
class="filter-item"
value-format="yyyy-MM-dd"
type="date"
placeholder="考试结束时间"
/>
<el-input v-model="listQuery.params.title" placeholder="搜索考试名称" style="width: 200px;" class="filter-item" />
</template>
<template slot="data-columns">
<el-table-column
label="考试名称"
prop="title"
/>
<el-table-column
label="考试类型"
align="center"
>
<template slot-scope="scope">
{{ scope.row.openType | examOpenType }}
</template>
</el-table-column>
<el-table-column
label="考试时间"
width="220px"
align="center"
>
<template slot-scope="scope">
<span v-if="scope.row.timeLimit">
{{ scope.row.startTime }} ~ {{ scope.row.endTime }}
</span>
<span v-else>不限时</span>
</template>
</el-table-column>
<el-table-column
label="考试总分"
prop="totalScore"
align="center"
/>
<el-table-column
label="及格线"
prop="qualifyScore"
align="center"
/>
<el-table-column
label="状态"
align="center"
>
<template slot-scope="scope">
{{ scope.row.state | examStateFilter }}
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="220px"
>
<template slot-scope="scope">
<el-button type="primary" size="mini" icon="el-icon-edit" @click="handleUpdateExam(scope.row.id)">修改</el-button>
<el-button type="warning" size="mini" icon="el-icon-user" @click="handleExamDetail(scope.row.id)">考试详情</el-button>
</template>
</el-table-column>
</template>
</data-table>
</template>
<script>
import DataTable from '@/components/DataTable'
export default {
name: 'ExamList',
components: { DataTable },
data() {
return {
openTypes: [
{
value: 1,
label: '完全开放'
},
{
value: 2,
label: '指定部门'
}
],
listQuery: {
current: 1,
size: 10,
params: {
title: ''
}
},
options: {
// 可批量操作
multi: true,
// 批量操作列表
multiActions: [
{
value: 'delete',
label: '删除'
}, {
value: 'enable',
label: '启用'
},
{
value: 'disable',
label: '禁用'
}
],
// 列表请求URL
listUrl: '/exam/api/exam/exam/paging',
// 删除请求URL
deleteUrl: '/exam/api/exam/exam/delete',
// 删除请求URL
stateUrl: '/exam/api/exam/exam/state',
addRoute: 'AddExam'
}
}
},
methods: {
handleExamDetail(examId) {
this.$router.push({ name: 'ListExamUser', params: { examId: examId }})
},
handleUpdateExam(examId) {
this.$router.push({ name: 'UpdateExam', params: { id: examId }})
}
}
}
</script>
步骤3,在src=>components=>pagination页码组件:
<template>
<div :class="{ 'hidden': hidden }" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to'
export default {
name: 'Pagination',
data() {
return {
layout: 'total, sizes, prev, pager, next, jumper'
}
},
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
mounted() {
if (this._isMobile()) {
this.deviceType = 'mobile'
this.layout='total, sizes, prev, pager, next'
} else {
this.deviceType = 'pc'
this.layout='total, sizes, prev, pager, next, jumper'
}
},
methods: {
//判断设备是手机端还是pc端
_isMobile() {
let flag = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)
return flag;
},
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
/* padding: 32px 16px; */
}
.pagination-container.hidden {
display: none;
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具