功能介紹:
在移動端開發中,會用到列表作為信息展示方式,一般希望上下滾動時,可以固定表頭,左右滾動時,可以固定最左列。
需求:
1、列表可以使用數組循環遍歷;
2、上下滾動時,可以固定表頭在最頂端顯示;
3、左右滾動時,可以固定左邊一列或多列可以固定顯示;
4、列表的列寬允許在數組中設置;
思路:
1、頁面使用四個dom元素分別存儲四種元素:
1)固定在左上角,完全不參與滾動表頭元素;
2)固定在頂部,只允許左右滾動表頭元素;
3)固定在左側,只允許上下滾動列元素;
4)右下角,左右上下均可隨意滾動列元素;
2、表頭數組與列表數據數組之間互相聯系,表頭屬性可以控制列表列排序、列表寬度、是否為固定列等;
3、四個dom之間增加聯動,使用@scroll、scrollLeft、scrollTop;
示意圖:
實現代碼:
html代碼:
<div class="table-box"><div class="listFlexSty"><div class="fixedHeadBox" :style="{width: fixedWid}"><divclass="thClass"v-for="(item, index) in fixedHead":key="index":style="{width: item.width, justifyContent:item.name === '名稱'?'flex-start':'',padding:item.name === '名稱'?'0 10px':''}"@click="thItemClick(item)"><div>{{item.name}}</div><div class="playIconSty"><div class="topArrow"></div><div class="bottomArrow"></div></div></div></div><divclass="nomalHeadBox"style="{width: 'calc(100% - ' + fixedWid + ')';}"><div ref="nomalHeadBox" @scroll="scrollHList"><div class="thClass" :style="{width: nomalWid}"><divclass="thClass"v-for="(item, index) in nomalHead":key="index":style="{width: item.width,padding:item.name === '折扣偏差'?'0 10px':''}"@click="thItemClick(item)"><div>{{item.name}}</div><div class="playIconSty"><div class="topArrow"></div><div class="bottomArrow"></div></div></div></div></div></div></div><div style="height: calc(100% - 40px); overflow: auto" id="dataBodyId"><div v-show="tBodyData.length!==0" class="listFlexSty"><div class="fixedListBox" :style="{width: fixedWid}"><div ref="fixedListBox" @scroll="scrollFList"><div class="rLineSty" v-for="(item, index) in tBodyData" :key="index"><divv-for="(it, inx) in fixedHead":key="inx":style="{width: it.width, justifyContent:it.name === '名稱'?'flex-start':'',padding:it.name === '名稱'?'0 10px':''}"class="thClass"><span v-if="it.prop === 'storeName' || it.prop === 'curDiscount'">{{item[it.prop]}}</span><spanv-if="it.prop === 'orderAmount' || it.prop === 'diffAmount'"v-format="'#,##0.##'">{{item[it.prop]}}</span><span v-if="it.prop === 'completionRate'">{{item[it.prop]}}%</span><spanv-if="it.prop === 'yearEarlier'":class="item[it.prop]<0?'downArrow':item[it.prop]>0?'upArrow':''">{{item[it.prop]}}%</span><span v-if="it.prop === 'diffDiscount'">{{item[it.prop]>0?'+':''}}{{item[it.prop]}}</span></div></div></div></div><divclass="nomalListBox"ref="nomalListBox":style="{width: 'calc(100% - '+fixedWid+')'}"@scroll="scrollList"><divclass="rLineSty":style="{width: nomalWid}"v-for="(item, index) in tBodyData":key="index"><divv-for="(it, inx) in nomalHead":key="inx":style="{width: it.width,padding:it.name === '折扣偏差'?'0 10px':''}"class="thClass"><span v-if="it.prop === 'storeName' || it.prop === 'curDiscount'">{{item[it.prop]}}</span><span v-if="it.prop === 'orderAmount' || it.prop === 'diffAmount'" v-format="'#,##0.##'">{{item[it.prop]}}</span><span v-if="it.prop === 'completionRate'">{{item[it.prop]}}%</span><spanv-if="it.prop === 'yearEarlier'":class="item[it.prop]<0?'downArrow':item[it.prop]>0?'upArrow':''">{{item[it.prop]}}%</span><span v-if="it.prop === 'diffDiscount'">{{item[it.prop]>0?'+':''}}{{item[it.prop]}}</span></div></div></div></div><div v-show="tBodyData.length>0 && !finished" class="bottomTip" @click="moreLoad"><span style="color: #999999">展開查看更多</span><van-icon name="arrow-down" color="#999999" /></div><div v-show="tBodyData.length>0 && finished" class="bottomTip"><span style="color: #999999">已加載完全部數據</span></div><div v-show="tBodyData.length===0" class="noData">暫無數據</div></div>
</div>
js代碼:
data(){return {// 下面是首頁底部列表數據相關字段tHeadData: [{ name: '名稱', prop: 'storeName', width: '100px', isfixed: true },{ name: '總業績(元)', prop: 'orderAmount', width: '80px' },{ name: '平均折扣', prop: 'curDiscount', width: '80px' },{ name: '同比', prop: 'yearEarlier', width: '60px' },{ name: '完成率', prop: 'completionRate', width: '80px' },{ name: '缺口(元)', prop: 'diffAmount', width: '100px' },{ name: '折扣偏差', prop: 'diffDiscount', width: '80px' }],tBodyData: [],fixedHead: [],nomalHead: [],fixedWid: '',nomalWid: ''}
},methods: {// 列表數據相關initData() {this.fixedHead = this.tHeadData.filter(item => {return item.isfixed;});this.nomalHead = this.tHeadData.filter(item => {return !item.isfixed;});this.initSize();},initSize() {let fwid = 0;let nwid = 0;this.fixedHead.forEach(item => {// 此處以px單位為例const len = item.width.length - 2;const width = item.width.substring(0, len) - 0;fwid += width;});this.nomalHead.forEach(item => {const len = item.width.length - 2;const width = item.width.substring(0, len) - 0;nwid += width;});this.fixedWid = fwid + 'px';this.nomalWid = nwid + 'px';},// 首頁下方數據列表聯動相關scrollHList() {this.$refs.nomalListBox.scrollLeft = this.$refs.nomalHeadBox.scrollLeft;},scrollFList() {this.$refs.nomalListBox.scrollTop = this.$refs.fixedListBox.scrollTop;},scrollList() {this.$refs.fixedListBox.scrollTop = this.$refs.nomalListBox.scrollTop;this.$refs.nomalHeadBox.scrollLeft = this.$refs.nomalListBox.scrollLeft;}
}
css代碼:
.table-box {width: 100%;height: calc(100% - 80px);overflow: hidden;
}
.listFlexSty {display: flex;
}
.fixedHeadBox {height: 40px;line-height: 40px;color: #333333;font-size: 12px;
}
.nomalHeadBox {height: 40px;line-height: 40px;overflow: hidden;color: #333333;font-size: 12px;
}
.fixedListBox {height: 100%;overflow: hidden;color: #666666;font-size: 12px;
}
.nomalListBox {height: 100%;overflow: auto;color: #666666;font-size: 12px;
}
.thClass {display: flex;align-items: center;justify-content: flex-end;
}
.rLineSty {height: 34px;padding: 10px 0;display: flex;
}
.rLineSty > div {display: -webkit-box;-webkit-line-clamp: 2;overflow: hidden;
}/* 隱藏滾動條 */
/* 隱藏右邊表格頭部滾動條 */
.nomalHeadBox > div {overflow: auto;height: calc(100% + 10px);
}
/* 隱藏左邊列表滾動條 */
.fixedListBox > div {overflow: auto;height: 100%;width: calc(100% + 10px);
}
.noDataNew {height: calc(100% - 40px);display: flex;align-items: center;justify-content: center;color: #999;font-size: 12px;
}
效果圖:
注意: 代碼里的方法thItemClick
是列排序功能,與此文章無關,實現代碼未貼出,除此之外,其他未貼出的代碼均與此文章所講功能無關,忽略即可。