1、需求场景
在实际的项目开发中,表格是使用最多的数据展示方式,如果每个页面都重写一遍表格代码,那么项目会变得越来越冗余,也不满足vue的设计理念,为了代码的简洁高效,可维护、可扩展,就需要封装table组件,全局调用
2、 参考element-ui,根据官方提供的api,进行代码的二次封装,将所需要的参数和方法封装暴露出去
<template>
<div v-if="headerData.length">
<el-table
ref="elTable"
size="small"
width="100%"
:border="border"
:stripe="stripe"
v-loading="loading"
element-loading-text="数据加载中"
element-loading-spinner="el-icon-loading"
v-bind="$attrs"
v-on="$listeners"
:data="tableData"
:height="height"
:max-height="maxHeight"
:row-key="getRowKeys"
@sort-change="handleSort"
@select="handleSelect"
@select-all="handleSelectAll"
@selection-change="handleSelectionChange"
@filter-change="filterData"
>
<el-table-column
v-if="radio"
type="radio"
:width="headerOptions.width"
:fixed="headerOptions.fixed"
align="center"
>
<template v-slot="scope">
<el-radio
v-model="selectedRadio"
:disabled="!selectable(scope.row)"
:label="scope.row[rowKey]"
@change="handleRadioChange"
>
{{ '' }}
</el-radio>
</template>
</el-table-column>
<el-table-column
v-if="selection"
:reserve-selection="reserveSelection"
type="selection"
:selectable="selectable"
:width="headerOptions.width"
:fixed="headerOptions.fixed"
align="center"
></el-table-column>
<el-table-column
v-if="index"
type="index"
label="序号"
align="center"
:width="headerOptions.indexWidth"
:fixed="headerOptions.indexFixed"
>
<template v-slot="scope">
<div class="text-center">
{{ scope.$index + (currentPage - 1) * pageSize + 1 }}
</div>
</template>
</el-table-column>
<template v-for="column of headerData">
<el-table-column
v-if="column.children && column.children.length && column.visible !== false"
:header-align="column.headerAlign || 'center'"
:fixed="column.fixed"
:min-width="column.minWidth"
:key="column.prop"
:label="column.label"
v-bind="getColumnProps(column.columnProps)"
>
<template v-for="child of column.children">
<el-table-column
v-if="child.visible !== false"
:header-align="child.headerAlign || 'center'"
:fixed="child.fixed"
:min-width="child.minWidth"
:key="child.prop"
:align="child.align"
:width="child.width"
:label="child.label"
:prop="child.prop"
:sortable="child.sortable"
:formatter="child.formatter"
:show-overflow-tooltip="child.overflow"
v-bind="getColumnProps(child.columnProps)"
>
<template v-slot="scope">
<table-content :context="scope" :config="child"></table-content>
</template>
</el-table-column>
</template>
</el-table-column>
<el-table-column
v-else-if="column.visible !== false"
:header-align="column.headerAlign || 'center'"
:min-width="column.minWidth"
:fixed="column.fixed"
:key="column.prop"
:align="column.align"
:width="column.width"
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:formatter="column.formatter"
:filters="column.filters"
:filter-method="column.filterMethod"
:column-key="column.columnKey"
:show-overflow-tooltip="column.overflow"
v-bind="getColumnProps(column.columnProps)"
>
<template v-slot="scope">
<table-content :context="scope" :config="column"></table-content>
</template>
</el-table-column>
</template>
</el-table>
<Pagination
v-if="showPagination"
v-bind="pageOptions"
:single="single"
:small="small"
:current-page="currentPage"
:page-size="pageSize"
:total="total"
@showPages="handleSize"
@changePage="handlePage"
/>
</div>
</template>
<script>
import Pagination from '@/components/Pagination'
import TableContent from './table-content'
export default {
inheritAttrs: false,
name: 'yq-table',
props: {
rowKey: {
type: String,
default: 'objId'
},
index: {
default: true,
type: Boolean
},
showPagination: {
default: true,
type: Boolean
},
showIndex: {
default: true,
type: Boolean
},
border: {
default: true,
type: Boolean
},
stripe: {
default: true,
type: Boolean
},
reserveSelection: {
default: false,
type: Boolean
},
pageOptions: {
type: Object,
default: () => {}
},
options: {
type: Object,
default: () => {}
},
currentPage: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 10
},
selectable: {
type: Function,
default: _ => _
},
radio: Boolean,
single: Boolean,
small: Boolean,
selection: Boolean,
loading: Boolean,
tableData: Array,
total: Number,
height: [String, Number],
maxHeight: [String, Number],
headerData: Array
},
data() {
return {
selectedRadio: ''
}
},
computed: {
headerOptions() {
const baseOpts = {
width: '60px',
fixed: false,
indexWidth: '60px',
indexFixed: false
}
return Object.assign({}, baseOpts, this.options)
}
},
methods: {
getRowKeys(row) {
return row.id
},
getColumnProps(val) {
if (typeof val !== 'object') return null
return val
},
handleRadioChange(val) {
const item = this.tableData.filter(i => i[this.rowKey] === val) || []
this.$emit('select-change', item)
},
handleSort(column, prop, order) {
this.$emit('table-sort', column, prop, order)
},
handleSelectionChange(val) {
this.$emit('select-change', val)
},
filterData(val) {
console.log(val)
this.$emit('filter-data', val)
},
handleSelectAll(val) {
this.$emit('select-all', val)
},
handleSelect(val, row) {
this.$emit('select', val, row)
},
handlePage(val) {
this.$emit('now-page', val)
},
handleSize(val) {
this.$emit('now-size', val)
}
},
components: {
TableContent,
Pagination
}
}
</script>
3、所要使用的地方引入组件
import Table from '@/components/Table'
components: { Table }
tableData:[],
tableHeader :[
{
label: '名称',
prop: 'applyName',
align: 'center',
overflow: true
},
]
.
.
需要传递给组件的参数在data中定义,接口赋值后组件接收渲染dom节点
// 获取列表数据
getTableData() {
this.loading = true
this.getTableParams()
highQualityPage(this.tableParams)
.then(res => {
this.loading = false
this.tableData = res.result
for (let i = 0; i < this.tableData.length; i++) {
//接口获取数据
this.tableData[i].id = this.tableData[i].applyId
this.tableData[i].dispatchStatus =
this.tableData[i].dispatchStatus == '' ? false : this.tableData[i].dispatchStatus
this.tableData[i].execStatusName =
this.executionStatus.find(item => item.value == this.tableData[i].execStatus)
?.label || '--'
}
this.total = res.total
})
.catch(() => {
this.loading = false
})
},
4、文章小结
因为表格组件是开发人员不可绕过的功能,也是使用最多的功能组件,所以为了使项目简洁高效,封装是必不可少的,项目中各种需求层出不穷,所以也需要我们开发人员考虑健全,尽可能做到组件高可扩展性,这样也才能提高开发效率。有疑问的朋友可以私我,咱们共同探讨。