无论是后台管理系统,还是数据报表类项目,表格总是少不了的,尤其是在手机上做APP的时候,复杂报表也是很常见,每遇到一个都用代码做一遍会不会觉得很烦,程序员最喜欢的可是–懒,但是要想偷懒必须先勤快,把组件做了,后面copy。
项目中做中国式表格会很常见,特点就是:列特别多、多行复合表头、表头可冻结、列可冻结、要支持很多行-几千几万行那种;如果只是普通的表格,完全不用任何组件,结合Bootstrap的样式,使用VUE强大的数据绑定功能就可实现,比如下面这样:
<table class="table table-bordered table-striped" v-loading="loading">
<thead>
<tr>
<th>系统</th>
<th>应用名称</th>
<th>姓名</th>
<th>访问时间</th>
<th class="text-left">page_ID</th>
<th>页面名称</th>
</tr>
</thead>
<tbody>
<tr v-for="row in logs">
<td>{
{
row.platformId}}</td>
<td>{
{
row.appName}}</td>
<td class="text-center">{
{
row.userName}}</td>
<td>{
{
new Date(row.createTime).toLocaleString()}}</td>
<td>{
{
row.pageId}}</td>
<td>{
{
row.pageName}}</td>
</tr>
</tbody>
</table>
注:上面没有列出分页组件的使用,这个自己查下文档就知道怎么用了。
不过,上面的方式并不通用,因为我们经常遇到复杂表头,还有的需要让表头固定,让表内容单独滚动,有时还要固定左侧某些列,让右侧滚动,有的需要支持编辑功能,这种情况下,再用原始报表去做就比较麻烦了,每一个都得写一遍很苦恼有木有?大多数人都会想到ElementUI里的表格组件,使用el-row这些拼,不过我觉得Elements的表格做的并不好用,稍微复杂点就得写很多代码,甚至踩很多坑。因此,我放弃了Elements的表格,自已基于原生的table实现了表格和对应的分页。
前端要实现一个表格组件无非有两种方式:
1、基于DIV实现一个纯div式的表格,这种实现方式完全摆脱了table的束缚,功能会比较强大,缺点就是实现复杂,嵌套很多的DIV会拖累性能,而且基于scroll事件的滚动不会很流畅。如果格子里的内容较多,溢出的话就没法支持自动换行,行高需要固定死。
2、基于table进行封装,这种方式实现相对简单,能结合table的轻量、兼容性好的特点,但如果要实现复杂格式,也很麻烦,做冻结也要基于scroll事件做滚动,但整体比较轻量,而且行高可以根据内容自动适应。
这两种方式中第二中是主流,国内很少有第一种实现的好用组件。本文也是基于第2种方案实现的。
废话不多说,直接上代码,下面代码可以直接使用,后面有使用样例。
1、表格组件
<template>
<div class="response-table">
<div class="fixed-table-head">
<div class="fixed-head">
<table class="table table-bordered">
<thead>
<tr v-for="cols in sourceColumns">
<th v-for="col in cols" v-if="col.vh!==false" @click="columnClick(col)" :class="[col.colclass||'',orderIndex===col.id?'active':'']" :style="{width:col.w}" :colspan="col.colspan||1" :rowspan="col.rowspan||1">{
{
col.name}}<a v-if="hasOrder(col)" class="arrow-order" :class="{ceil:col.order===1,floor:col.order===-1}"><i class="fa fa-caret-up"></i><i class="fa fa-caret-down"></i></a></th>
</tr>
</thead>
</table>
</div>
<div class="response-body">
<div v-if="isLoading" class="text-center"><i class="fa fa-3x fa-spinner fa-spin" ></i></div>
<div v-if="emptytip && (sourceList==null||sourceList.length==0)" class="emptytip">
{
{
emptytip}}
</div>
<table class="table table-bordered table-striped">
<tbody>
<tr v-if="!bodyrender" v-for="(row,index) in sourceList" :class="rowStyle(row,index)">
<td v-for="col in fields"
v-if="(row.$R==null)||(row.$R!=null && row.$R[col.field].render)"
:rowspan="row.$R==null?1:row.$R[col.field].rowspan"
:colspan="row.$R==null?1:row.$R[col.field].colspan||1"
:style="{width:col.w}"
@click="cellClick(row,col,index,$event)"
:class="c(row,col,index)">
<span v-if="!col.template" v-html="v(row,col,index)" :class="cc(row,col,index)"></span>
<span v-if="col.template" v-html="parsetemplate(row,col,index)" :class="cc(row,col,index)" @click="templateClick(row,col,index,$event)"></span>
</td>
</tr>
<tr v-if="bodyrender" v-for="(row,index) in sourceList" :class="rowStyle(row,index)">
<td v-for="col in fields" v-if="row.$R[col.field].render" :rowspan="row.$R[col.field].rowspan" :style="{width:col.w}" :class="c(row,col,index)" :title="col.name">
<span v-html="v(row,col,index)" :class="cc(row,col,index)"></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default{
name: 'ResponseTable',
props: {
emptytip:{
type:String,
required:false
},
list:{
type: Array,
required: true
},
columns: {
type: Array,
required: true
},
rowclass:{
type:Function,
required:false
},
bodyrender:{
type:Boolean,//每行数据可维护一个$R字段列表,指出是否要渲染,以及rowspan和colspan,用于合并单元格
default:false
},
selectable:{
type:Boolean, default:false
},
multiselect:{
type:Boolean, default:false
}
},
data(){
return {
inited:false,
orderIndex:null,
isLoading:false,
sourceList:this.list,
sourceColumns:this.columns
}
},
mounted(){
//如果初始化进来的数据有值,则执行默认排序
if(this.sourceList.length>0){
//进行默认排序:找出columns中order不为0或null的第一个字段进行排序
for(var i=0;i<this.columns.length;i++){
if(this.columns[i].order===1||this.columns[i].order===-1){
this.orderIndex=this.columns[i].id;
this.reOrder(this.columns[i]);
break;
}
}
}
},
watch:{
'list':function(n,o){
this.sourceList=n;
this.clearSelected();
}
},
computed: {
fields()

最低0.47元/天 解锁文章
1124

被折叠的 条评论
为什么被折叠?



