vue + element 实现的可配置的数据搜索组件(搜索框 + table展示 + 分页控制)
说明:
在管理系统中,涉及到很多根据查询条件,查出数据,然后使用表格展示的页面。
对于这种复用性极强的page,提供一个公共的组件是很必要的(样式统一、高效开发)。
主要切分为3个组件。
1、Filter 功能:搜索条件,搜索按钮
2、Table 功能:展示数据,列表内实现一些操作如:查看、编辑等
3、Pagination 功能:分页,控制页面大小,页面数
调用方式:
<template lang="pug">
FilterTable(
:list="list"
:filters="filters"
:tableList="tableList"
:pageNum="pageNum"
:pageSize="pageSize"
:total="total"
@listenHandleClickFilterButton="handleClickFilterButton"
@listenHandleClickTableColumnHref="handleClickTableColumnHref"
@listenHandleChangePaginationSize="handleChangePaginationSize"
@listenHandleChangePaginationNum="handleChangePaginationNum"
)
</template>
import FilterTable from '@/components/common/c-filter-table'
import list from './list'
export default {
components: {
FilterTable
},
created() {},
data() {
return {
pageNum: 1,
pageSize: 20,
total: 0,
tableList: [],
list,
filters: list.filterList.reduce((obj, item) => {
if (item.type !== 'button') {
obj[item.key] = ''
}
return obj
}, {}),
}
},
methods: {
handleClickFilterButton(buttonKey) {
if (buttonKey === 'search') {
this.handleClickSearch()
}
if (buttonKey === 'reset') {
this.handleClickReset()
}
if (buttonKey === 'export') {
this.handleClickExport()
}
if (buttonKey === 'add') {
this.handleClickAdd()
}
},
handleClickTableColumnHref(columnKey, row) {
if (columnKey === 'edit') {
console.log('click column edit')
}
},
handleChangePaginationSize(size) {
this.pageNum = 1
this.pageSize = size
this.handleClickSearch()
},
handleChangePaginationNum(num) {
this.pageNum = num
this.handleClickSearch()
},
async handleClickSearch() {
...
},
handleClickAdd() {
...
},
async handleClickReset() {
this.filters = list.filterList.reduce((obj, item) => {
if (item.type !== 'button') {
obj[item.key] = ''
}
return obj
}, {})
...
}
}
}
复制代码
参数说明
list:搜索框配置、表格字段配置
一个list配置如下:
const list = {
filterList: [
{
label: '座位号',
key: 'id',
type: 'input',
span: 6
},
{
label: '班级',
key: 'class',
type: 'select',
options: [
{
key: '1',
label: '一班',
val: '1'
},
{
key: '2',
label: '二班',
val: '2'
}
],
span: 6
},
{
label: '入学日期',
key: 'statPeriod',
type: 'datePicker',
span: 6,
config: {
type: 'date',
placeholder: '选择日期'
}
},
{
label: '入校时长',
key: 'backDate',
type: 'datePicker',
config: {
type: 'daterange',
rangeSeparator: '至',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期'
},
span: 12
},
{
label: '查询',
key: 'search',
type: 'button',
config: {
type: 'primary'
},
span: 2
},
{
label: '重置',
key: 'reset',
type: 'button',
config: {
type: ''
},
span: 2
},
{
label: '导出',
key: 'export',
type: 'button',
config: {
type: 'success'
},
span: 2
}
],
tableColumns: [
{
label: '状态',
key: 'stateName'
},
{
label: '编号',
key: 'code'
},
{
label: '姓名',
key: 'name'
},
{
label: '年龄',
key: 'remark'
},
{
label: '操作',
key: 'edit',
type: 'href',
filter: () => '编辑'
}
],
复制代码
filterList
用于配置搜索框 对应的事件处理为:listenHandleClickFilterButton
tableColumns
用于配置表格字段 对应的事件处理为:listenHandleClickTableColumnHref
tableList: 搜索结果,传入table
的数据
pageNum、pageSize、total: 分页需要的数据
对应的控制分页事件为:listenHandleChangePaginationSize、listenHandleChangePaginationNum
c-filter-table
完整代码:
<template lang="pug">
.c-table-container
el-form.search-box
el-row(:gutter="20")
template(v-for="item in list.filterList")
el-col(
v-if="item.type==='button'"
:span="item.span"
:key="item.key")
el-button(:type="item.config.type" @click="handleClickFilterButton(item.key)") {{ item.label }}
el-col(
v-else
:span="item.span"
:key="item.key")
el-form-item(
:label="item.label"
:prop="item.key"
label-width="110px")
el-input(
v-if="item.type==='input'"
v-model="filters[item.key]")
el-select(
v-if="item.type==='select'"
v-model="filters[item.key]")
el-option(
v-for="option in item.options"
:key="option.key"
:value="option.val"
:label="option.label")
el-select(
v-if="item.type==='select-filterable'"
v-model="filters[item.key]"
filterable placeholder="请选择")
el-option(
v-for="option in item.options"
:key="option.key"
:value="option.val"
:label="option.label")
el-date-picker(
v-if="item.type==='datePicker'"
v-model="filters[item.key]"
:type="item.config.type"
:range-separator="item.config.rangeSeparator"
:start-placeholder="item.config.startPlaceholder"
:end-placeholder="item.config.endPlaceholder")
el-table(:data="tableList" border)
el-table-column(
type="index"
label="序号"
align="center")
el-table-column(
v-for="item in list.tableColumns"
:key="item.key"
:label="item.label"
:prop="item.key"
align="center")
template(slot-scope="scope")
a(
v-if="item.type === 'href'"
class="blue"
@click="handleClickTableColumnHref(item.key, scope.row)"
) {{ item.filter(scope.row) }}
span(v-else) {{ item.filter ? item.filter(scope.row) : scope.row[item.key] }}
el-pagination(
@size-change="handleChangePaginationSize"
@current-change="handleChangePaginationNum"
:page-sizes="[10, 20, 50, 100]"
:current-page.sync="selfPageNum"
:page-size="selfPageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total")
</template>
<script>
export default {
props: [
'list',
'tableList',
'total',
'pageNum',
'pageSize',
'filters',
'listenHandleClickFilterButton',
'listenHandleClickTableColumnHref',
'listenHandleChangePaginationSize',
'listenHandleChangePaginationNum'
],
data() {
return {
selfPageNum: this.pageNum,
selfPageSize: this.pageSize
}
},
methods: {
handleClickFilterButton(filterKey) {
this.$emit('listenHandleClickFilterButton', filterKey)
},
handleClickTableColumnHref(columnKey, row) {
this.$emit('listenHandleClickTableColumnHref', columnKey, row)
},
handleChangePaginationSize(val) {
this.selfPageNum = 1
this.selfPageSize = val
this.$emit('listenHandleChangePaginationSize', val)
},
handleChangePaginationNum(val) {
this.selfPageNum = val
this.$emit('listenHandleChangePaginationNum', val)
}
}
}
</script>
<style scoped lang="scss">
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.el-col {
border-radius: 4px;
}
.blue {
color: #409eff;
}
.c-table-container {
padding: 15px;
min-height: 500px;
.search-box.el-form {
display: flex;
flex-wrap: wrap;
.el-form-item {
.el-input {
width: 160px;
}
}
}
.extand {
.el-form-item {
width: 25%;
}
}
.el-pagination {
text-align: right;
padding: 10px;
}
}
</style>
复制代码