uniapp封装固定表头、固定列表格
最近⼜有个很烦的需求,就是要在平板上渲染⼀张⼤表格,⽽且表格需要在向上滚动时固定表头,向左滚动时固定左侧列,uniapp是不⽀持table的,⽹上的也很难到合适的组件,这就尴尬了。
第⼀时间想的是⽤scroll-view来做,也真就这么搞了,也搞出来,通过各种计算固定了表头和左侧列,但是最让⼈头疼的问题就是性能太低,H5端没问题,移动端在滚动的时候会有延迟效果,⽽且滚动快了会错位,还有就是抖动,硬伤!
后来想到了sticky,尝试了⼀下,还真可⾏,写了个组件,由于是给项⽬写的,封装具有局限性,⼤家有能⽤得着的就拿去改改吧,这个组件⽀持左侧固定表格的⼀级⼤分类,上代码吧!
<template>
<view class="table">
<view class="cCon">
<view class="outInBlock">
<view class="title">
{{headerTitle}}
</view>
<scroll-view scroll-y="true" scroll-x="true"class="xscoll">
<view class="time-box">
<view class="cheader" id="left":>
<view class="left">
<view class="text"></view>
</view>
</view>
<view class="title" id="title":>
<view class="time-block" v-for="(head,index) in tableHeader":key="index":>
<slot name="header":header="head"></slot>
{{!$scopedSlots.header ?(headerKey ? head[headerKey]: head):''}}
</view>
</view>
</view>
<view class="left":>
<view class="classify">
<view class="block" v-for="(item,index) in classifyData":key="index":>
<slot name="classifyItem":classifyItem="item"></slot>
{{!$scopedSlots.classifyItem ?(classifyDataKey?item[classifyDataKey]:item):''}}
</view>
</view>
<view class="classifyBox">
<view class="leftbox":id="getdom(n,item)" v-for="(item,n) in tableContentLeftFixed":key="n">
<view class="outInTitle":>
<slot name="leftFix":leftFix="item"></slot>
{{!$scopedSlots.leftFix ?(leftFixKey?item[leftFixKey]:item):''}}
</view>
</view>
</view>
</view>
<view class="right-box">
<view class="right": v-for="(item,n) in tableContent":key="n">
<view class="bot">
<view class="infoNum" v-for="(data,i) in item[contentKey]":key="i":>
<slot name="content":content="data"></slot>
{{!$t ?(unitKey?data[unitKey]:data):''}}
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
<script>
/**
* table 表格
* @description 固定表头和左侧表格组件
* @property {Array} tableHeader 头部数据固定
* @property {Array} tableContentLeftFixed 左侧数据固定
* @property {Array} tableContent body部分数据
* @property {String} headerKey 当不使⽤slot修改头部,渲染数据的属性
* @property {String} leftFixKey 当不使⽤slot修改左侧固定栏,渲染数据的属性
* @property {String} contentKey 当不使⽤slot修改body展现数据第⼀层,渲染数据的属性  * @property {String} unitKey 当不使⽤slot修改body展现数据第⼆层,渲染数据的属性
* @property {String} leftFixWidth 左侧固定列的宽度
* @property {String} classify 左侧有分类分级时需要传⼊⽤来做⼤类区分的属性名
* @property {Array} classifyData 传⼊的最左侧⼤分类数据
* @property {String} headerTitle 表格的title
* @property {Object} headerStyle 修改表头单元格样式
* @property {Object} leftFixStyle 修改左侧固定栏单元格样式
* @property {Object} contentStyle 修改内容单元格样式
* @example <v-table :tableContentLeftFixed="tableContentLeftFixed"
:tableHeader="tableHeader"
:tableContent="tableContent"
:classifyData="classifyData"
:headerStyle="headerStyle"
:headerTitle="headerTitle"
leftFixWidth="15%"
contentKey="content"
unitKey="name"
classify="id"
classifyDataKey="name">
<template v-slot:header="{header}">
<view>{{header.name}}</view>
</template>
<template v-slot:leftFix="{leftFix}">
<view>{{leftFix.name}}</view>
</template>
<template v-slot:content="{content}">
<view>{{content}}</view>
</template>
<template v-slot:classifyItem="{classifyItem}">
<view>{{classifyItem}}</view>
</template>
</v-table>
*/
export default{
props:{
tableHeader:{
type: Array,
default:()=>[]
},
tableContentLeftFixed:{
type: Array,
default:()=>[]
},
tableContent:{
type: Array,
default:()=>[]
},
headerKey:{
type: String,
default:null
},
leftFixKey:{
type: String,
default:null
},
contentKey:{
type: String,
default:null
},
unitKey:{
type: String,
default:null
},
},
leftFixWidth:{
type: String,
default:'25%'
},
classify:{
type: String,
default:null
},
classifyData:{
type: Array,
default:()=>[]
},
headerTitle:{
type: String,
default:null
},
headerStyle:{
type: Object,
default(){
return{
minWidth:'100px',
color:'#333',
fontSize:'18px',
}
}
},
leftFixStyle:{
type: Object,
default(){
return{
minWidth:'100px',
color:'#333',
fontSize:'14px',
}
}
},
contentStyle:{
type: Object,
default(){
return{
minWidth:'100px',
color:'#333',
fontSize:'18px',
}
}
}
},
data(){
return{
domEles:{},
domIDs:{},
classifyDom:{}
}
},
watch:{
domEles:{
handler:function(val){
debugger
let keysArray = Object.keys(this.domIDs)
if(!keysArray.length)return
let num =1,n =0,self =this;
const query = ateSelectorQuery().in(this);
for(let i=0;i<keysArray.length;i++){
for(let j=1;j<=this.domIDs[keysArray[i]];j++){
console.log(self.domEles)
console.log(self.domEles)
self.classifyDom.hasOwnProperty(i)?self.$set(self.classifyDom,i,self.classifyDom[i]+val[n]):self.$set(self.classifyDom,i,val[n]);      n++;
}
}
},
deep:true,
// immediate: true
},
tableContentLeftFixed:{
handler:function(val){
debugger
let self =this;
let i;
this.tableContentLeftFixed.forEach((data,index)=>{
if(i !== data[self.classify]){
i = data[self.classify]
self.$set(self.domIDs,data[self.classify],1)
}else{
self.$set(self.domIDs,data[self.classify],self.domIDs[data[self.classify]]+1)
}
})
},
deep:true,
/
/ #ifdef H5
immediate:true
// #endif
}
},
borderboxcreated(){
console.log(this)
},
methods:{
getdom(n,item){
let self =this;
this.$nextTick(function(){
const query = ateSelectorQuery().in(this);
query.select('#dom'+n).boundingClientRect(data =>{
if(data){
self.$set(self.domEles,n,data.height)
}else{
}
}).exec();
})
return'dom'+n
}
}
}
</script>
<style lang="scss" scoped>
.table{
width:100%;
height:100%;
flex:1;
background-color: transparent;
display: flex;
flex-direction: column;
padding:032rpx;
box-sizing: border-box;
.cCon{
width:100%;
height:100%;
height:100%;
flex:1;
position: relative;
z-index:2;
.outInBlock{
display: flex;
position: relative;
flex-direction: column;
z-index:1;
height:calc(100%-40px);
.title{
text-align: center;
}
.xscoll{
overflow-x: auto;
overflow-y: hidden;
width:100%;
top:-80rpx;
height:100%;
flex:1;
.time-box{
height:40px;
width:100%;
top:0;
position: sticky;
left:0;
z-index:18;
background: #f5f5f5;
.cheader{
width:25%;
display: flex;
position: sticky;
left:0;
z-index:3;
border-right:2rpx solid color(bd1);      box-sizing: border-box;
background-color:color(bg);
.left{
display: flex;
align-items: center;
width:25%;
height:80rpx;
line-height:80rpx;
color:color(th);
visibility: hidden;
display: flex;
.text{
margin-left:30rpx;
}
}
}
.title{
display: flex;
justify-content: center;
align-items: center;
height:80rpx;
line-height:80rpx;
position: absolute;
top:0;
left:25%;
background-color:color(bg);
z-index:1;
.time-block{
flex:1;
height:100%;
min-width:202rpx;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。