vue之封装一个 table组件 ( 列表之中 渲染其他组件 )
listTable / index.vue
<template>
<div class="search-table">
<!-- v-loading="listLoading" -->
<el-table
ref="searchTable"
:data="tablelist"
border
stripe
size="mini"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange"
@cell-click="handleCellClick"
>
<el-table-column v-if="isSelect" type="selection" width="55" />
<el-table-column
v-else
label="序号"
width="65px"
type="index"
:index="indexMethod"
align="center"
/>
<template v-for="item in columns">
<el-table-column
v-if="!item.hidden"
:key="item.prop"
:prop="item.prop"
:label="item.label"
:sortable="item.sortable"
:width="item.width"
:min-width="item.minWidth"
:formatter="item.render"
:render-header="item.renderHeader"
:show-overflow-tooltip="!item.hiddenTooltip"
>
<template
v-if="item.formatter && typeof item.formatter !== 'function'"
v-slot:default="{ row, column, $index }"
>
<component
:is="item.formatter"
:key="row.id"
:table-data="tablelist"
:row="row"
:column="column"
:index="$index"
:col="item"
:cell-value="row[item.prop]"
:status="item.status"
/>
</template>
<template v-else-if="item.link" v-slot:default="{ row, column }">
<span class="jump-color" @click="handleOperate(row, column)">{{
row[item.prop]
}}</span>
</template>
</el-table-column>
</template>
<el-table-column v-if="isAction" label="操作" :width="operation[0].width ? operation[0].width : 120 ">
<template v-slot:default="{ row, index }">
<div v-for="(item, key) in operation" :key="key" class="opt-btn">
<span
v-if="checkRenderStatus(row, item)"
class="operate-btn"
:disabled="checkDisabled(row, item)"
@click="handleOperate(item, index, row)"
>
{{ item.label }}
</span>
</div>
</template>
</el-table-column>
</el-table>
<!-- @size-change="handleSizeChange" :page-sizes="pagesizes"-->
<el-pagination
v-if="!hiddenPagination"
class="table-pagination"
layout="total, prev, pager, next"
:total="total"
:page-size="pagesize"
:current-page="currentPage"
@current-change="handlePageChange"
/>
</div>
</template>
<script>
export default {
name: 'SearchTable',
props: {
isInit: {
type: [Boolean, String],
default: false
},
searchForm: {
type: Object,
default: () => {}
},
defalutData: {
type: Array,
default: () => {
return []
}
},
url: {
type: String,
default: () => {
return ''
}
},
requestMethod: {
type: String,
default: () => {
return 'GET'
}
},
columns: {
type: Array,
default: () => {
return []
}
},
hiddenPagination: {
type: Boolean,
default: false
},
operation: {
type: Array,
default: () => {
return []
}
},
origin2formated: {
type: Function,
default(val) {
return val
}
},
isSelect: {
type: Boolean,
default: () => {
return false
}
}
},
data() {
return {
tablelist: [],
total: 0,
pagesize: 20,
currentPage: 1,
currentOrderStr: null
}
},
computed: {
offset() {
return (this.currentPage - 1) * this.pagesize
},
isAction() {
return this.operation && this.operation.length > 0
}
},
created() {
if (this.isInit) return
this.fetchData()
},
methods: {
indexMethod(index) {
return index + 1 + (this.currentPage - 1) * this.pagesize
},
resetPage() {
this.currentPage = 1
},
async fetchData() {
const info = {}
const params = {
limit: this.pagesize,
offset: this.offset,
ordering: this.currentOrderStr,
...this.searchForm
}
console.log('params', params)
this.tablelist = [
{
pathUrl: '/about11',
errorType: 1,
status: 1,
txt_time: '2022-08-24 17:27:49'
},
{
pathUrl: '/about12',
errorType: 2,
status: 0,
txt_time: '2022-08-24 17:27:49'
}
]
return info
},
handlePageChange(val) {
this.currentPage = val
this.fetchData()
},
handleOperate(item, index, row) {
const operateInfo = {
item: item,
index: index,
row: row
}
this.$emit('handleOperate', operateInfo)
},
handleSortChange({ column, prop, order }) {
if (order === null) {
this.currentOrderStr = null
} else if (order === 'descending') {
this.currentOrderStr = '-' + prop
} else {
this.currentOrderStr = prop
}
this.fetchData()
},
handleCellClick(row, column, cell, event) {
const payload = { row, column, cell, event }
this.$emit('handleCellClick', payload)
},
checkRenderStatus(row, operation) {
if (operation.alwaysShow) {
return true
}
const role = this.$store.state.user.role
const accessedRoles = operation.accessedRoles || []
if (accessedRoles.length > 0 && accessedRoles.indexOf(role) < 0) {
return false
}
const defaultShowbyRow = {
key: null,
value: []
}
const showByRow = Object.assign(defaultShowbyRow, operation.showByRow)
if (showByRow.key != null && showByRow.value.length !== 0) {
const actionValue = row[showByRow.key]
if (showByRow.value.indexOf(actionValue) < 0) {
return false
}
}
return true
},
checkDisabled(row, operation) {
const showDisabled = operation.showDisabled
if (showDisabled) {
return row[showDisabled.key] !== showDisabled.value
} else {
return false
}
},
handleSelectionChange(val) {
this.$emit('handleOperate', val)
},
clearSelection() {
this.$refs['searchTable'].clearSelection()
}
}
}
</script>
<style lang="scss" scoped>
.search-table {
.table-pagination {
margin-top: 10px;
margin-bottom: 10px;
text-align: center;
}
.opt-btn {
display: inline;
&:not(:first-child) {
.el-button {
margin-left: 5px;
}
}
}
.operate-btn {
margin-right: 10px;
font-size: 14px;
color: rgba(64, 158, 255, 1);
cursor: pointer;
}
}
</style>
table组件相关
base.vue
<template>
<div />
</template>
<script>
export default {
name: 'BaseFormatter',
props: {
row: {
type: Object,
default: () => ({})
},
column: {
type: Object,
default: null
},
index: {
type: Number,
default: 0
},
col: {
type: Object,
default: () => ({})
},
cellValue: {
type: [String, Boolean, Number, Object, Array],
default: null
}
},
data() {
return {}
}
}
</script>
DataFormatter.vue 时间格式化
<template>
<span>{{ iDateTime }}</span>
</template>
<script>
import BaseFormatter from './base'
export default {
name: 'DataFormatter',
extends: BaseFormatter,
computed: {
iDateTime() {
let res = ''
this.cellValue ? res = this.cellValue.substring(0, 10) : ''
return res
}
}
}
</script>
TagStatusFormatter.vue 状态格式化
<template>
<el-tag v-if="iType" :type="iType" effect="plain" size="small">{{ iLabel }}</el-tag>
</template>
<script>
import BaseFormatter from './base.vue'
export default {
name: 'TagStatusFormatter',
extends: BaseFormatter,
props: {
status: {
type: Object,
default: () => {}
}
},
data() {
return {}
},
computed: {
iType() {
return this.status[this.cellValue]?.type
},
iLabel() {
return this.status[this.cellValue]?.label
}
}
}
</script>
LinkTo.vue ( 跳转组件 )
<template>
<div class="assets-id-copy">
<div class="router-link" @click="goto">
{{ row.pathUrl }}
</div>
</div>
</template>
<script>
import BaseFormatter from './base.vue'
export default {
name: 'LinkTo',
extends: BaseFormatter,
props: {
row: {
type: Object,
default: () => {}
}
},
data() {
return {}
},
computed: {
url() {
const pathUrl = this.row.pathUrl
return pathUrl
}
},
methods: {
goto() {
this.$router.push(this.url)
}
}
}
</script>
<style lang="scss" scoped>
.assets-id-copy {
display: flex;
.router-link {
color: #0000ff;
cursor: pointer;
&:hover {
text-decoration: none;
color: #606266;
}
}
}
</style>
使用组件
···js
User2
<list-table ref="searchTable" v-bind="tableConfig" :search-form="searchForm" @handleOperate="handleOperate" />
···
效果
|