一.、新建一个表格的Component
1.table.vue内容如下
<template>
<div class="lb-table">
<el-table
ref="elTable"
v-bind="$attrs"
:stripe="stripe"
:border="border"
:data="data"
row-key="id"
:tree-props="{children: '_child', hasChildren: 'hasChildren'}"
size="medium"
v-on="$listeners"
>
<template v-for="item in column">
<template>
<!-- 操作列表 -->
<el-table-column
v-if="item.prop == 'action'"
:key="item.prop"
v-bind="$attrs"
:prop="item.prop"
:label="item.label"
:fixed="item.fixed"
:type="item.type"
:index="item.index"
:column-key="item.columnKey"
:width="item.width"
:min-width="item.minWidth"
:sortable="item.sortable || false"
:sort-method="item.sortMethod"
:sort-by="item.sortBy"
:sort-orders="item.sortOrders"
:resizable="item.resizable || true"
:formatter="item.formatter"
:show-overflow-tooltip="item.showOverflowTooltip || true"
:align="item.align || 'center'"
:header-align="item.headerAlign || item.align || 'center'"
:class-name="item.className"
:label-class-name="item.labelClassName"
:selectable="item.selectable"
:reserve-selection="item.reserveSelection || false"
:filters="item.filters"
:filter-placement="item.filterPlacement"
:filter-multiple="item.filterMultiple"
:filter-method="item.filterMethod"
:filtered-value="item.filteredValue"
>
<template slot-scope="scope">
<el-button
v-for="(act, actionIndex) in item.children"
:key="actionIndex"
type="text"
:class="{danger: act['event'] === 'handleDelete'}"
@click="handleAction(act,scope.row)"
>{{ act.name }}</el-button>
</template>
</el-table-column>
<!-- 普通列表 -->
<el-table-column
v-else
:key="item.prop"
v-bind="$attrs"
:prop="item.prop"
:label="item.label"
:type="item.type"
:index="item.index"
:column-key="item.columnKey"
:width="item.width"
:min-width="item.minWidth"
:sortable="item.sortable || false"
:sort-method="item.sortMethod"
:sort-by="item.sortBy"
:sort-orders="item.sortOrders"
:resizable="item.resizable || true"
:formatter="item.formatter"
:show-overflow-tooltip="item.showOverflowTooltip || true"
:align="item.align || 'center'"
:header-align="item.headerAlign || item.align || 'center'"
:class-name="item.className"
:label-class-name="item.labelClassName"
:selectable="item.selectable"
:reserve-selection="item.reserveSelection || false"
:filters="item.filters"
:filter-placement="item.filterPlacement"
:filter-multiple="item.filterMultiple"
:filter-method="item.filterMethod"
:filtered-value="item.filteredValue"
>
<template slot-scope="scope">
<slot
:scope="handleScope(scope)"
:name="item.prop"
>
{{ scope.row[item.prop] }}
</slot>
</template>
</el-table-column>
</template>
</template>
</el-table>
<el-pagination
v-if="pagination"
class="table-pagination"
v-bind="$attrs"
v-on="$listeners"
@current-change="currentChange"
@size-change="sizeChange"
/>
</div>
</template>
<script>
export default {
props: {
column: Array,
data: Array,
pagination: {
type: Boolean,
default: false
},
stripe: {
type: Boolean,
default: false
},
border: {
type: Boolean,
default: false
}
},
data() {
return {
mergeLine: {},
mergeIndex: {}
}
},
methods: {
handleAction(e, item) {
console.log('编辑啊', e, item)
this.$emit(e.event, item)
},
handleScope({ row, $index, column }) {
return { row, $index, column }
},
clearSelection() {
this.$refs.elTable.clearSelection()
},
toggleRowSelection(row, selected) {
this.$refs.elTable.toggleRowSelection(row, selected)
},
toggleAllSelection() {
this.$refs.elTable.toggleAllSelection()
},
toggleRowExpansion(row, expanded) {
this.$refs.elTable.toggleRowExpansion(row, expanded)
},
setCurrentRow(row) {
this.$refs.elTable.setCurrentRow(row)
},
clearSort() {
this.$refs.elTable.clearSort()
},
clearFilter(columnKey) {
this.$refs.elTable.clearFilter(columnKey)
},
doLayout() {
this.$refs.elTable.doLayout()
},
sort(prop, order) {
this.$refs.elTable.sort(prop, order)
},
currentChange(val) {
this.$emit('p-current-change', val)
},
sizeChange(val) {
this.$emit('size-change', val)
}
}
}
</script>
<style scoped lang="scss">
@import "@/styles/variables.scss";
.button {
margin: 0 5px;
padding: 0;
border: none;
background: none;
color: $menuActiveText;
}
.danger {
color: #f56c6c;
}
.table-pagination{
margin-top: 15px;
display: flex;
justify-content: flex-end;
}
</style>
2.全局引入(main.js)
import CustomTable from '@/components/Table/table'
Vue.component('CustomTable', CustomTable)
3.mixin公用方法配置
(1)新建mixin文件
(2)tableMixin内容如下
/**
* data中url定义 list为查询列表 delete为删除单条记录 deleteBatch为批量删除
*/
import { getAction, postAction, deleteAction } from '@/api/manage'
import { filterObj } from '@/utils/index'
export const tableMixin = {
data() {
return {
/* 查询条件-请不要在queryParam中声明非字符串值的属性 */
queryForm: {},
/* 数据源 */
dataSource: [],
/* 分页参数 */
pagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '30'],
showTotal: (total, range) => {
return range[0] + '-' + range[1] + ' 共' + total + '条'
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
/* table加载状态 */
loading: false
}
},
created() {
if (!this.disableMixinCreated) {
this.loadData()
}
},
methods: {
loadData(arg) {
if (!this.url.list) {
this.$message.error('请设置url.list属性!')
return
}
// 加载数据 若传入参数1则加载第一页的内容
if (arg === 1) {
this.pagination.current = 1
}
var params = this.getQueryParams()
this.loading = true
getAction(this.url.list, params).then((res) => {
if (res.code === 0) {
this.dataSource = res.data.list || res.data
if (res.data.total) {
this.pagination.total = res.data.total
} else {
this.pagination.total = 0
}
} else {
this.$message.warning(res.msg)
}
}).finally(() => {
this.loading = false
})
},
search(form) {
this.queryForm = form
this.loadData(1)
},
getQueryParams() {
// 获取查询条件
var param = this.queryForm
param.page = this.pagination.current
param.per_page = this.pagination.pageSize
return filterObj(param)
},
selectionChange(selection) {
if (selection.length) {
this.show = {
...this.show,
batch: true
}
} else {
this.show = {
...this.show,
batch: false
}
}
this.table = {
...this.table,
selection
}
console.log('selection', selection, this.show, this.table)
},
onClearSelected() {
this.$refs.foxTable.$refs.elTable.clearSelection()
this.table.selection = []
},
searchReset() {
this.queryForm = {}
this.loadData(1)
},
batchDel: function() {
if (!this.url.deleteBatch) {
this.$message.error('请设置url.deleteBatch属性!')
return
}
if (this.table.selection.length <= 0) {
this.$message.warning('请选择一条记录!')
return
} else {
var ids = ''
for (var a = 0; a < this.table.selection.length; a++) {
ids += this.table.selection[a] + ','
}
var that = this
this.$confirm({
title: '确认删除',
content: '是否删除选中数据?',
onOk: function() {
that.loading = true
deleteAction(that.url.deleteBatch, { ids: ids }).then((res) => {
if (res.success) {
// 重新计算分页问题
that.reCalculatePage(that.table.selection.length)
that.$message.success(res.msg)
that.loadData()
that.onClearSelected()
} else {
that.$message.warning(res.msg)
}
}).finally(() => {
that.loading = false
})
}
})
}
},
handleDelete: function(item) {
const that = this
if (!that.url.delete) {
this.$message.error('请设置url.delete属性!')
return
}
that.$confirm('确定要删除当前数据?', '提示', { type: 'warning' }).then(
() => {
postAction(that.url.delete, { id: item.id }).then((res) => {
if (res.code === 0) {
// 重新计算分页问题
that.reCalculatePage(1)
that.$message.success('删除成功')
console.log('删除成功')
that.loadData()
} else {
that.$message.warning(res.msg)
}
})
}
)
},
reCalculatePage(count) {
// 总数量-count
const total = this.pagination.total - count
// 获取删除后的分页数
const currentIndex = Math.ceil(total / this.pagination.pageSize)
// 删除后的分页数<所在当前页
if (currentIndex < this.pagination.current) {
this.pagination.current = currentIndex
}
console.log('currentIndex', currentIndex)
},
handleEdit: function(record) {
this.$refs.modalForm.show(record)
},
handleAdd: function() {
this.$refs.modalForm.show()
},
// 分页改变
handleTableChange(current) {
this.pagination.current = current
this.loadData()
},
// 分页总码改变
handleSizeChange(size) {
this.pagination.pageSize = size
this.loadData()
}
}
}
(3)标注一下tableMixin里引入的内容
// utils/index里的方法filterObj
//为了方便单独将方法放在这里展示,实际在所引入的文件里面
/**
* 过滤对象中为空的属性
* @param obj
* @returns {*}
*/
export function filterObj(obj) {
if (!(typeof obj === 'object')) {
return
}
for (const key in obj) {
if (obj.hasOwnProperty(key) &&
(obj[key] === null || obj[key] === undefined || obj[key] === '')) {
delete obj[key]
}
}
return obj
}
// api/manage 文件的方法
//为了文章写的方便单独将方法放在这里展示,实际在所引入的文件里面
import axios from 'axios'
// post
export function postAction(url, parameter, cache = false, setExpireTime) {
return axios({
url: url,
method: 'post',
data: parameter
})
}
// get
export function getAction(url, parameter, cache = false, setExpireTime) {
return axios({
url: url,
method: 'get',
params: parameter,
cache,
setExpireTime
})
}
// deleteAction
export function deleteAction(url, parameter) {
return axios({
url: url,
method: 'delete',
params: parameter
})
}
3.table里面的README.vue文件内容如下(以及使用说明):
# table 帮助文档使用说明
## 参数配置
| 参数 | 类型 | 必填 | 说明 |
|--------------|---------|------|---------------------------------------------------------------------------------|
| columns | array | ✔️ | 表格列的配置描述,具体项见下表 |
| data | array | ✔️ | 表格数据 |
| loading | boolean | | 是否正在加载,加载中不会显示任何行,默认false |
| pagination | boolean | | 是否显示分页,默认false |
| current-page | number | | 当前分页数 |
| total | number | | 数据总数 |
| page-size | number | | 每次分页数 |
## column参数配置
| 参数 | 类型 | 必填 | 说明 |
|----------------------- |----------------|------|---------------------------------------------------------------------------------|
| fixed | string | | 定位 left/right |
| type | string | | 对应列的类型 |
| index | boolean | | 是否正在加载,加载中不会显示任何行,默认false |
| column-key | string | | column 的 key |
| label | string | | 显示的标题 |
| prop | string | | 对应列内容的字段名 |
| width | number | | 对应列的宽度 |
| sortable | boolean,string | |默认false,对应列是否可以排序,如果设置为 'custom',则代表用户希望远程排序 |
| show-overflow-tooltip | Boolean | |默认为true, 当内容过长被隐藏时显示 tooltip |
| align | string | | 对齐方式, 默认center, left/center/right |
| header-align | string | | 表头对齐方式, 默认center,left/center/right |
| class-name | string | | 列的 className |
| label-class-name | string | | 当前列标题的自定义类名 |
## 事件
| 事件名 | 触发时机 | 参数 |
|-----------------|----------------------------------------------------|--------------------------------------------------|
| p-current-change| 当currentPage 改变时会触发 | |
| selection-change | 当行被选中或取消选中时触发 | |
| size-change | 当pageSize 改变时会触发 | |
## 使用例子
已经全局引入,无需单个页面引入
<template>
<custom-table
v-loading="table.loading"
:column="table.column"
:data="dataSource"
pagination
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="pagination.current"
:total="pagination.total"
:page-size="pagination.pageSize"
@p-current-change="handleTableChange"
@selection-change="selectionChange"
@size-change="handleSizeChange"
@handleEdit="handleEdit"
@handleDelete="handleDelete">
</custom-table>
</template>
```javascript
<script>
import {tableMixin} from '@/mixins/tableMixin'
export default{
mixins: [tableMixin],
data(){
return{
table: {
data: [],
column: [
{
label: '操作',
prop: 'action',
fixed: 'right',
children: [
{
name: '编辑',
event: 'handleEdit'
},
{
name: '删除',
event: 'handleDelete'
}
]
},
{
label: 'ID',
prop: 'id',
width: 80
},
{
label: '账号',
prop: 'username'
},
],
loading: false,
},
page: { //分页参数
pageNum: 1,
pageSize: 10,
total: 0
},
url: {
list: '', //列表请求接口路径
}
}
}
}
</script>