大家好,我是wo不是黄蓉,今年学习目标从源码共读开始,希望能跟着若川大佬学习源码的思路学到更多的东西。
讲一些比较实用的东西,相信我们经常会用表单和表格实现查询列表功能,通常做法是同一个页面中编写列表,编写表单项,且多个页面相同布局时重复代码多,代码量大。
我们可以通过配置实现表单项和表格列,
实现思路:
- 通过插槽实现页面布局,然后使用不同的插槽实现表单和表格的自定义。
- 封装表单项组件,通过接收配置项来生成表单和表格
- 表单项中有的为输入框组件,有的为下拉组件,可以通过配置项传入参数,然后组件里面使用
component :is='xxx'
属性来实现表单项里面内容自定义
代码实现:
TableLayout
<template>
<div class="table_layout_container">
<div class="table_form">
<slot name="form"> </slot>
</div>
<el-divider></el-divider>
<div class="table_body_wrap">
<div class="flex_box table_operation">
<div class="table_left flex_box">
<div class="table_header_line"></div>
<div class="table_header_content">
<slot name="title">列表</slot>
</div>
</div>
<div class="table_right">
<slot name="btn"></slot>
</div>
</div>
<div class="table_container">
<div class="table-content"><slot name="table"></slot></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TableLayout',
};
</script>
<style lang="scss" scoped>
@import '@/styles/components/table-layout.scss';
</style>
TableColumns
<template>
<el-table
:border="showBorder"
:data="data"
:stripe="stripe"
:height="height"
tooltip-effect="dark"
align="center"
@row-click="rowClick"
@row-dblclick="rowDblclick"
>
<el-table-column
:label="indexLabel"
v-if="showIndex"
type="index"
width="50"
align="center"
>
</el-table-column>
<el-table-column
v-for="(item, index) in columns"
:key="index"
:prop="item.prop"
:label="item.label"
:width="String(item.width)"
:min-width="String(item.minWidth)"
:show-overflow-tooltip="true"
align="center"
>
<template slot-scope="scope">
<slot v-if="item.showSlot" :name="`${item.prop}`" :scope="scope"></slot>
<template v-else>{{ scope.row[item.prop] }}</template>
</template>
</el-table-column>
<el-table-column
:show-overflow-tooltip="true"
:width="String(operatorWidth)"
v-if="showOperator"
label="操作"
label-width="80px"
align="center"
>
<template slot-scope="scope">
<slot name="default" :scope="scope"></slot>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
name: 'TableColumns',
props: {
data: {
type: Array,
default: () => [],
},
columns: {
type: Array,
default: () => [],
},
//是否展示操作栏
showOperator: {
type: Boolean,
default: false,
},
//操作栏宽度
operatorWidth: {
type: Number,
default: 100,
},
//是否展示边框
showBorder: {
type: Boolean,
default: true,
},
//是否展示序列
showIndex: {
type: Boolean,
default: false,
},
//自定义序列label
indexLabel: {
type: String,
default: '序号',
},
height: {
type: String,
default: 'calc(100% - 40px)',
},
maxHeight: {
type: String,
default: '500',
},
stripe: {
type: Boolean,
default: true,
},
},
methods: {
rowClick(row, column, event) {
this.$emit('rowClick', row, column, event);
},
rowDblclick(row, column, event) {
this.$emit('rowDblclick', row, column, event);
},
},
};
</script>
FormItems
<template>
<el-row>
<el-col :span="6" v-for="(item, index) in realColumns" :key="index">
<el-form-item
:label="item.label + ':'"
:prop="item.prop"
:label-width="item.labelWidth + 'px'"
>
<slot :name="item.prop" v-if="item.showSlot"></slot>
<component
v-else
size="mini"
v-model="formData[item.prop]"
:is="componentType(item.itemType)"
:clearable="item.clearable || true"
></component> </el-form-item
></el-col>
<el-col
:span="
realColumns.length % 4 === 1
? 18
: realColumns.length % 4 === 2
? 12
: realColumns.length % 4 === 0
? 24
: 6
"
>
<div class="flex_box">
<el-button type="primary" @click="onSearch" size="mini">搜索</el-button>
<el-button @click="onReset" size="mini">重置</el-button>
<span
class="no-border"
@click="changeCollapse"
v-if="configs.length > 3"
>{{ isExpand ? '展开' : '收起'
}}<i
:class="[
isExpand ? 'el-icon-arrow-down' : 'el-icon-arrow-up',
'el-icon--right',
]"
></i
></span>
</div>
</el-col>
</el-row>
</template>
<script>
import { cloneDeep } from 'lodash';
export default {
name: 'FormItems',
props: {
configs: {
type: Array,
default: () => [],
},
formData: {
type: Object,
default: () => {},
},
isExpand: {
type: Boolean,
default: false,
},
},
data() {
return {
isExpand: false,
};
},
computed: {
realColumns() {
let columns = [];
if (this.isExpand) {
columns = cloneDeep(this.configs).filter((item) => {
return !item.isCollapse;
});
} else {
columns = cloneDeep(this.configs);
}
return columns;
},
},
methods: {
componentType(itemType) {
if (typeof itemType === 'string') {
return `${itemType}`;
}
return itemType;
},
changeCollapse() {
this.isExpand = !this.isExpand;
},
onSearch() {
this.$emit('onSearch');
},
onReset() {
this.$emit('onReset');
},
},
};
</script>
<style lang="scss" scoped>
.flex_box {
justify-content: flex-end;
}
.el-button--small {
margin-left: 10px;
}
::v-deep {
.no-border {
display: inline-block;
border: none;
padding: 9px 15px;
margin-left: 10px;
color: #409eff;
font-size: 12px;
}
}
</style>
示例
<template>
<table-layout v-loading="loading">
<template slot="form">
<el-form :model="form" label-width="130px" label-position="right">
<form-items
:configs="configs"
:formData="form"
@onSearch="onSearch"
@onReset="onReset"
>
<template #date> 此处是date的自定义</template>
</form-items>
</el-form>
</template>
<template slot="btn">
<el-button type="primary" size="mini" @click="handleAdd(undefined, 'add')"
>新增 <i class="el-icon-plus"></i
></el-button>
</template>
<template slot="table">
<TableColumns
:data.sync="tableData"
:columns="columns"
:showOperator="true"
:operatorWidth="220"
height="calc(100% - 40px)"
>
<template #default="{ scope }">
<el-button type="text" @click="edit(scope.row)"
>编辑</el-button
></template
>
</TableColumns>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[8]"
:page-size="8"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</template>
</table-layout>
</template>
<script>
import { FormItems, FromData } from './config/form.js';
import { TableColumns } from './config/table.js';
import { page } from '@/mixins/page';
import { cloneDeep } from 'lodash';
export default {
name: 'DynamicTest',
mixins: [page],
data() {
return {
form: cloneDeep(FromData),
configs: cloneDeep(FormItems),
tableData: [],
columns: cloneDeep(TableColumns),
loading: false,
};
},
created() {
this.onSearch();
},
methods: {
onSearch() {
this.loading = true;
this.tableData = [];
setTimeout(() => {
this.tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄',
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄',
},
];
this.total = this.tableData.length;
this.loading = false;
}, 1000);
},
onReset() {
this.form = cloneDeep(FormData);
},
edit(row) {
console.log(row);
},
},
};
</script>
<style scoped lang="scss">
::v-deep {
.el-table th.el-table__cell {
background-color: #f5f5f5;
}
}
</style>
form.js
export const FormItems = [
{
label: '日期',
prop: 'date',
itemType: 'el-input',
labelWidth: 80,
showSlot: true,
},
{
label: '姓名',
prop: 'name',
itemType: 'el-input',
labelWidth: 130,
},
{
label: '地址',
prop: 'address',
itemType: 'el-input',
labelWidth: 80,
},
];
export const FromData = { date: '', name: '', address: '' };
table.js
export const TableColumns = [
{ label: '日期', prop: 'date' },
{ label: '姓名', prop: 'name' },
{ label: '地址', prop: 'address' },
];
效果展示
![](https://img.haomeiwen.com/i10131721/b64e2ec7bef0a183.png)
对element-ui
表单和表格的封装,更方便编写带查询的表格页面;支持根据js
配置生成表单项和表格列
所有的表单和表格项都是支持的,只是对原有的element-ui
提供的功能进行重新封装,多个表单项支持查询条件展开/折叠
Table Layout Slot
name | 说明 |
---|---|
form | 表格查询项自定义 |
title | 表格表头自定义 |
btn | 表格操作区域自定义 |
table | 表格自定义 |
FormItems Attributes
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
configs | 表单项列表 | Array | [] | |
formData | 表单项数据 | Array | [] | |
isExpand | 是否默认展开查询条件,默认不展开 | Boolean | true/false | false |
FormItems Methods
方法名 | 说明 | 参数 |
---|---|---|
onSearch | 点击搜索时回调函数 | |
onReset | 点击清空时回调函数 |
FormItems 和 Table Slot
1.需要在config中添加`showSlot`为`true`
2.配置name为`prop`的slot
TableColumns Attributes
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
data | 表格数据项 | Array | [] | |
columns | 表格列 | Array | [] | |
showOperator | 是否展示操作栏 | Boolean | false | |
operatorWidth | 操作栏宽度 | Number | 100 | |
showBorder | 是否展示边框 | Boolean | true | |
showIndex | 是否展示序列 | Boolean | false | |
indexLabel | 自定义序列 label | String | 序号 | |
height | 自定义表格高度 | String | calc(100% - 40px) | |
maxHeight | 表格最大高度 | String | 500 | |
stripe | 是否使用斑马线 | Boolean | true |
TableColumns Methods
方法名 | 说明 | 参数 |
---|---|---|
rowClick | 单击行事件 | row, column, event |
rowDblclick | 双击行事件 | row, column, event |
网友评论