之前加入一个项目 用的element-ui写的后台管理,发现很多问题
结束之后自己总结经验重新二次封装tabel组件方便下次新项目开发。
功能: 集成了分页,自动计算高度,自动计算宽度,分页选择记忆功能,自定义表格内容,数据过滤
tabel.vue
<div class="dataTable" >
<!--<div v-if="add.url" style="padding: 20px">-->
<!--<router-link class="inlineBlock" :to="add.url"> <el-button type="primary" >{{add.title}}</el-button></router-link>-->
<!--</div>-->
<div class="table" ref="dataTable">
<el-table border
:data="nowList"
ref="dtable"
highlight-current-row
:height="autoHeight?height:null"
style="width: 100%;overflow: auto"
v-loading="obj.isLoading"
@selection-change="handleSelectionChange"
@cell-click="cellClick"
@select-all="selectAll"
:row-class-name="tableRowClassName"
:max-height="height">
<el-table-column
v-if="showSelect"
align="center"
prop="isShow"
width="55"
label="多选框"
fixed="left"
:render-header="renderCheckBox">
>
<template slot-scope="scope">
<el-checkbox v-model="scope.row.isCheck" @change="changeOne(scope.row)" ></el-checkbox>
</template>
</el-table-column>
<!--数据源-->
<el-table-column
v-for="column in columns"
v-if="column.isShow&&!column.scope"
align="center"
:sortable="column.hasSort"
:show-overflow-tooltip="tooltip"
:key="column.prop"
:prop="column.prop"
:width="calculationWidth(column)"
:sort-by="column.prop"
:sort-method="column.method"
:fixed="column.fixed"
:label="column.label">
<template slot-scope="scope">
<div v-if="column.render">
<render :render="column.render" :params="scope"></render>
</div>
<div v-else>
{{scope.row | itemFilter(column)}}
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="heJi" v-if="hasAll">
<span>合计</span>
<div v-for="item in allColumns">
<span>{{item.label}}:</span>
<span>{{allObj |itemFilter(item)}}</span>
</div>
</div>
<div class="page"v-if="hasPage">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="obj.page.page"
:page-sizes="[10, 20, 30, 40,50,100]"
:page-size="obj.page.rows"
layout="total, sizes, prev, pager, next"
:total="parseInt(obj.page.totalCount)||0">
</el-pagination>
<i class="el-icon-refresh" @click="refresh"></i>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import render from './render'
import type from '../../utils/type'
import {mapGetters} from "vuex"
import {lang} from '../../utils/lodash.js'
/*向父组件传递的数据:
* commitSelection 被选中的数据
*
* */
export default {
name: "tm-table",
components:{
render,
},
filters:{
itemFilter(value,column){
if(column.filter){
return column.filter(value[column.prop])
}
return value[column.prop]
}
},
props: {
keyId:{ //当初出现多选 主键用来区分每条记录的唯一Key 必传
type:String,
default:function() {
return ""
}
},
tableRowClassName:{
type:Function,
default:function () {
return ""
}
},
hasAll:{
type:Boolean,
default() {
return false
}
},
allObj:{
},
allColumns:{
type:Array,
default(){
return []
}
},
tooltip: {
type: Boolean,
default: true
},
hasPage:{
type:Boolean,
default:function () {
return true
}
},
//自适应父及高度
autoHeight:{
type:Boolean,
default:function () {
return true
}
},
// 这是相应的字段展示
columns: {
type: Array,
default: function() {
return [];
}
},
// 这是数据源
obj: {
type: Object,
default: function() {
return {
list:[],
page:1,
size:10
}
}
},
showSelect: {
type:Boolean,
default:function () {
return false
}
}
},
created(){
this.$nextTick(()=>{
//this.height=this.$refs.dataTable.offsetHeight - (this.hasPage?85:0)
this.height=this.$refs.dataTable.offsetHeight
})
this.nowList=lang.cloneDeep(this.list);
},
watch:{
navStyle(){
this.$nextTick(()=>{
this.height=this.$refs.dataTable.offsetHeight
})
},
list(){
this.nowList=lang.cloneDeep(this.list);
}
},
mounted(){
},
data(){
return {
BASE_URL: process.env.BASE_API,
height:400,
allList:[],
nowList:[],
}
},
computed:{
...mapGetters(['navStyle']),
list(){
var list
if(this.keyId&&this.showSelect) {
list = lang.cloneDeep(this.obj.list.map(item => {
item.isCheck = item.isCheck ? true : false
let isOk = false
for (let value of this.allList) {
if (item[this.keyId] == value[this.keyId]) {
item.isCheck = value.isCheck
value = item
isOk = true;
break
}
}
if (!isOk) {
this.allList.push(item)
}
return item
}))
}
else{
list=lang.cloneDeep(this.obj.list)
}
return list
},
checkAll(){
if(this.list.length==0){
return false
}
for(let value of this.nowList){
if(!value.isCheck){
return false
}
}
return true
}
},
methods: {
//筛选
filterList(fn){
this.nowList=lang.cloneDeep(this.list).filter((item)=>{
if(type.isFunc(fn)){
return fn(item)
}
return item
})
},
calculationWidth(item){
let name =item.label;
let widthNAuto=item.widthNAuto
if(widthNAuto){
return item.width||''
}
if(name){
let length=name.length;
let width=length*20+20;
return width+'px'
}
else {
return ""
}
},
setCurrent(index) {
this.$refs.dtable.setCurrentRow(this.list[index]);
},
selectRow(){
//选择的记录 配合ref取出组件里选择值
return this.allList.filter(item=>{
return item.isCheck==true
})
},
emptySelectRow(){//清空选中项,查询条件更改时会出现原来的选中项还是选中的
this.allList = this.allList.map(item=>{
item.isCheck=false;
return item;
})
},
//将选中的行发送到父组件
changeOne(item,bin){
this.allChange(item)
},
allChange(item){
if(this.keyId&&this.showSelect){
for(let value of this.allList){
if(item[this.keyId]==value[this.keyId]){
value.isCheck=item.isCheck
}
}
}},
renderCheckBox(h,params){
return h('el-checkbox',{
props:{
value:this.checkAll
},
on:{
change:(item)=>{
let a =this.checkAll;
for(let value of this.nowList){
value.isCheck=!a
this.allChange(value)
}
}
}
})
},
sortFn(a,b){
// let ref=/^\d+(\.\d+)?\%?$/;
// if(ref.test(a)&&ref.test(b)){
// a=parseFloat(a.replace(/(\%)/,''));
// b=parseFloat(a.replace(/(\%)/,''));
// return a-b;
// }
// return a-b;
},
handleSelectionChange(val) {//多选 项发生改变
const selectionArr = [];
val.forEach(function(el) {
selectionArr.push(el);
});
this.$emit("handleSelectionChange", selectionArr);
},
handleSizeChange(pageSize){
this.obj.page.rows = pageSize;
this.$emit('select',this.obj.page)
},
handleCurrentChange(pageChange){
this.obj.page.page= pageChange;
this.$emit('select',this.obj.page)
},
cellClick(value) {
//行点击事件
this.$emit("commitClick", value);
},
delet(item){
this.allList= this.allList.filter((value)=>{
return value[this.keyId]!=item[this.keyId]
})
},
refresh(){
//刷新事件
this.$emit("refresh");
},
selectAll:function(selection){//用户全选时触发
this.$emit('selectAll',selection)
},
}
};
</script>
<style lang="less" rel="stylesheet/less" scoped>
.el-table {
width: 100%;
}
.table{
width: 100%;
overflow: auto;
display: flex;
flex: 1;
}
.heJi{
padding: 10px;
color: #606266;
display: flex;
>span{
padding: 0;
}
>div{
padding: 0 20px;
}
}
.page{
display: flex;
justify-content: flex-end;
padding-top: 10px;
align-items: center;
>i{
cursor: pointer;
}
}
</style>
<style lang="less">
.dataTable{
height: 100%;
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
flex: 1;
.el-table th{
background-color: #f9f9f9
}
.el-table th>.cell{
font-family: MicrosoftYaHei;
font-size: 14px;
font-weight: normal;
font-stretch: normal;
letter-spacing: 0px;
color: #004986;
}
/*.el-table .warning-row {*/
/*background: oldlace;*/
/*}*/
.el-table .success-row {
background: #7d94ed;
color: #ffffff;
}
.el-table .erro-row {
background: #bbc7f8;
color: #ffffff;
}
.el-table--enable-row-hover .el-table__body tr:hover>td {
background-color: #f5f7fa;
color:#606266;
}
}
.el-table__empty-block{
text-align: left!important;
}
</style>
render.js
export default {
name: 'cell',
functional: true,
props: {
params: Object,
render: Function,
},
render: (h, ctx) => {
const params = ctx.props.params
return ctx.props.render(h, params);
}
};
参数 |
参数类型 |
参数说明 |
默认值 |
obj |
<mark>Object,必传</mark> |
isLoading:Boolean遮罩层开关;list:Array数据源;page{page:1,rows:10,totalCount:总条数}分页参数 |
|
hasAll |
Boolean 非必传 |
是否显示合计 |
默认false |
allcolumns |
Array 非必传 |
合计显示内容 |
|
allObj |
Array 源 |
合计数据 |
默认false |
showSelect |
Boolean 非必传 |
选择框打开 |
默认false |
keyId |
String 非必传 |
需要记忆选择内容分页时候每条记录的主键 |
|
columns |
Array 必传 |
表格设置和element-ui columns类似新增加一些字段 |
|
columns 介绍 |
参数类型 |
参数说明 |
默认值 |
prop |
String 必传 |
数据的key |
|
label |
String 必传 |
显示的名字 |
|
isShow |
Boolean |
是否显示 |
true |
filter |
Function(item) |
过滤的方法 返回值为显示的内容 |
|
widthNAuto |
Boolean |
是否自动计算表格宽度 |
true |
width |
String '80px' |
宽度 widthNAuto=false 生效 |
true |
render |
Function(h,prams) |
vue render自定义组件 |
|
回调 |
作用 |
返回参数 |
refresh |
表格刷新 |
无 |
select |
分页发生变化 |
返回page参考传入的page |
|
内部方法 |
传入值 |
作用 |
返回值 |
filterList |
(Function(item) ) |
过滤数据(前端筛选) |
selectRow |
无 |
返回选择数据列 |
|
dele |
item 某条记录 |
删除表格记忆的数据 |
|
具体项目地址gihub
网友评论