vue二次封装ElementUI 的table组件
配置简介
- 直接给data 和 config,可以展示数据
- 给分页,和分页的接口方法,可以一键配置不用管, 目前分页参数固定,可以根据具体项目修改
- 如果有额外的请求条件,或者是搜索后展示,需要给queryParams
- 暂时只有select input link内置type,可以使用render自定义,亦可以自己增加额外的case
config
- key列的prop, label列表头显示
- render可以自定义渲染表身, 他陪type: custom 使用
- renderHeader 可以自定义渲染表头
- type是配置可编辑的表格使用, 如input,select,后期可以增加
- props 里的 disable,show,editable 为函数,参数是scope,返回boolean
- props是配置type后,使用的额外属性,只给可以编辑的dom使用, 如对input配置size,placeholder,select配置options都在这里使用
- 支持其他对el-table的所有属性和方法,支持对el-table-column所有属性,方法暂时没做
height
- 这个可选属性,如果不传,则默认到父组件的父级100%,table的高度是减去分页组件的高度
config = [
{
key: 'name',
label: '姓名',
type: 'custom',
renderHeader: (h, data) => {
return `姓名${data.row.$index}`
},
render: (h, data) => {
return `张三${data.row.$index}`
},
{
key: 'age',
label: '年龄',
type: 'input',
props: {
size: 'mini'
}
},
{
key: 'sex',
label: '性别',
type: 'select',
props: {
options: [
{
label: '男',
value: '1'
},
{
label: 'nv',
value: '2'
}
]
}
},
{
key: 'status',
label: '状态',
formatter: (row, column, cellValue, index) => {
return index%2 ? '启用' : '未启用'
}
}
}
]
组件代码
<script>
export default {
name: 'PTable',
model: {
prop: 'data',
event: 'change'
},
props: {
config: {
type: Array,
required: true
},
data: {
type: Array,
required: true
},
editable: {
type: Boolean,
default: true
},
height: {
type: Number
},
hasPagination: {
type: Boolean,
default: false
},
queryParams: {
type: Object,
default: () => ({})
},
queryApi: {
type: Function
}
},
data() {
return {
loading: false,
currentData: JSON.parse(JSON.stringify(this.data)),
pageSizes: [10, 25, 30, 50],
currentPageSize: 10,
currentPage: 4,
pageLayout: 'total, sizes, prev, pager, next, jumper',
pageTotal: 400
}
},
created() {
this.getTableData()
},
mounted() {
},
methods: {
handleTableChange(key, eventType, value) {
this.$emit('change', JSON.parse(JSON.stringify(this.currentData)))
this.$emit('table-change', key, eventType, value)
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.currentPageSize = val;
this.getTableData();
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.currentPage = val;
this.getTableData();
},
getTableData() {
if (!this.queryApi) return
let params = {};
params.pageNum = this.currentPage;
params.pageSize = this.currentPageSize;
Object.assign(params, this.queryParams);
this.loading = true;
this.queryApi(params).then(response => {
this.currentData = response.result_data;
this.pageTotal = response.count;
}).finally((error)=>{
this.loading = false;
})
}
},
render(h) {
const renderItem = (scope, data) => {
const { key, label, type, width, props, render, ...prop } = data
const canEdit = this.editable === false ? this.editable : (props.editable ? props.editable(scope) : true)
const isShow = props.show ? props.show(scope) : true
const isDisable = props.disable ? props.disable(scope) : false
let ItemTemplate = ''
if (canEdit) {
switch (type) {
case 'input':
ItemTemplate = <el-input v-model={scope.row[key]} placeholder={props.placeholder || '请输入'} size="mini" rows={props.rows} {...{props}} disabled={isDisable} onInput={() => this.handleTableChange(key, 'input', scope.row[key])} onBlur={() => this.handleTableChange(key, 'blur', scope.row[key])}></el-input>
break;
case 'link':
ItemTemplate = <el-link {...{props: props}} disabled={isDisable} onClick={() => props.click(scope)}>
{scope.row[key]}
</el-link>
break;
case 'select':
ItemTemplate = <el-select v-model={scope.row[key]} disabled={isDisable} placeholder={props.placeholder || '请输入'} size="mini" {...{props}} onChange={() => this.handleTableChange(key, 'change', scope.row[key])}>
{
props.options.map((item, index) => {
return <el-option
key={index}
label={item.label}
value={item.value}>
</el-option>
})
}
</el-select>
break;
case 'custom':
ItemTemplate = render(h, scope)
break;
default:
ItemTemplate = <span>{scope.row[key]}</span>
break;
}
} else {
ItemTemplate = <span>{scope.row[key]}</span>
}
return ItemTemplate
}
const renderChildren = (data) => {
const { key, label, type, width, props, children, ...prop } = data
let PROPS = {}
PROPS.type = type;
PROPS.prop = key;
PROPS.width = width;
PROPS.label = label;
PROPS.headerAlign = prop.headerAlign || 'center';
let ScopeS = {}
if (type === 'selection' || type === 'index') {
PROPS.align = 'center'
} else if (!type) {
Object.assign(PROPS, prop)
} else {
Object.assign(PROPS, prop)
ScopeS = {
scopedSlots: {
default: (scope) => {
return renderItem(scope, data)
}
}
}
if (prop.renderHeader) {
ScopeS.scopedSlots.header = (scope) => {
return prop.renderHeader(h, scope)
}
}
}
for (let [key, value] of Object.entries(PROPS)) {
(value == undefined) && delete PROPS[key]
}
return <el-table-column
{...{props: PROPS}}
{...ScopeS}>
{ children && children.length ? children.map(item => renderChildren(item)) : '' }
</el-table-column>
}
const tableHeight = this.height ? (this.height - (this.hasPagination ? 60 : 0) + 'px') : '0';
return(<div class="p-table-area" loading={this.loading}>
<section class="table-area" style={{ 'height': tableHeight }}>
<el-table
height="100%"
{...{props: this.$attrs}}
{...{on: this.$listeners}}
data={this.currentData}>
{
this.config.map((item) => {
return renderChildren(item)
})
}
</el-table>
</section>
{
this.hasPagination && <section class="page-area">
<el-pagination
onSizeChange={this.handleSizeChange}
OnCurrentChange={this.handleCurrentChange}
currentPage={this.currentPage}
pageSizes={this.pageSizes}
pageSize={this.currentPageSize}
layout={this.pageLayout}
total={this.pageTotal}>
</el-pagination>
</section>
}
</div>)
}
}
</script>
<style lang="scss" scoped>
.p-table-area {
flex: 1;
display: flex;
flex-direction: column;
width: 100%;
.table-area {
flex: 1;
}
.page-area {
height: 60px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
/deep/.el-table td {
padding: 4px 0;
}
/deep/.el-table th {
padding: 8px 0;
}
</style>