一、开发历程
开发过程中试过
1、使用粘性布局和固定粘性定位,固定定位,但都存在一些问题,比如:
1.1、粘性布局在安卓手机(如oppo、vivo)自带的浏览器中会失效,表头并不固定
1.2、滑动的过程中,表格会有拖拽的效果(看起来脱离了文档流,会出现空白,但松开会回弹回去)
1.3、在1.2的基础上,固定定位的首列扔定位在原处,让页面看起来分离成了三部分
2、最终方案
将表格划分为三部分,表头、首列、表格体。其中表格体的滚动效果通过overfloe:scroll实现,表头、首列通过表格体的滚动事件来动态设置绝对定位的偏移值来实现。
二、实现
1、HTML
<div class="content-table" v-show="tabActive == 2">
<!-- 表头 -->
<div class="rowHeader">
<table class="rowHeader-table" id="rowHeader-table">
<tr>
<td class="td seller_name tableH_fixed-left">销售员</td>
<td class="td seller_phone">手机号</td>
<td class="td one_branch">一级分校</td>
<td class="td two_branch">二级分校</td>
<td class="td total_uv double">累计访问人数</td>
<td class="td total_time double">累计访问时长(min)</td>
<td class="td add_uv double">昨日新增访问人数</td>
<td class="td add_time double">昨日新增访问时长(min)</td>
</tr>
</table>
</div>
<!-- 列头 -->
<div class="columnHeader">
<table class="columnHeader-table" id="columnHeader-table">
<tr v-for="(item, index) in sellersList" :key="index">
<td class="td seller_name">
{{ item.sellerName }}
</td>
</tr>
</table>
</div>
//表格滚动主体
<div class="tableBody" id="tableBody" @scroll="scrollFn($event)">
<table class="tableBody-table" id="tableBody-table">
<tr v-for="(item, index) in sellersList" :key="index">
<td class="td seller_phone">{{ item.sellerPhone }}</td>
<td class="td one_branch">{{ item.branchName }}</td>
<td class="td two_branch">{{ item.secondaryBranchName }}</td>
<td class="td total_uv">{{ item.totalUv }}</td>
<td class="td total_time">{{ item.totalVisitTime.toFixed(2) }}</td>
<td class="td add_uv">{{ item.increasedUv }}</td>
<td class="td add_time">{{ item.increasedVisitTime.toFixed(2) }}</td>
</tr>
</table>
</div>
</div>
</div>
2、css
.content-table {
position: absolute;
left: 16px;
top: 234px;
width: 343px;
height: calc(100% - 268px);
// 表头
.rowHeader {
position: relative;
width: 343px;
max-width: 343px;
overflow: hidden;
left: 0px;
// 表头table
.rowHeader-table {
position: relative;
width: fit-content;
height: 52px;
border-spacing: 0px;
.tableH_fixed-left {
position: sticky;
left: 0;
}
td {
display: flex;
justify-content: center;
align-items: center;
height: 52px;
color: #fff;
font-size: 14px;
background: #5b8ff9;
border-right: 1px solid #fff;
padding: 0px;
}
.seller_name {
border-radius: 16px 0 0 0;
}
}
}
// 列头
.columnHeader {
position: relative;
max-height: calc(100% - 55px);
overflow: hidden;
width: 80px;
top: 0px;
.columnHeader-table {
position: relative;
border-spacing: 0px;
tr {
background-color: #fff;
box-sizing: border-box;
td {
font-weight: 600;
border: 1px solid #f7f7f7;
border-top: none;
border-right: none;
}
&:first-child {
td {
padding: 0px;
box-sizing: border-box;
}
}
}
}
}
// 表格本体
.tableBody {
width: 265px;
max-height: calc(100% - 55px);
position: absolute;
top: 52px;
left: 80px;
overflow: auto;
.tableBody-table {
border-spacing: 0px;
tr {
height: 35px;
&:nth-child(odd) {
background: #e8f7ff;
// border: 0.02667rem solid #f7f7f7;
}
&:nth-child(even) {
background: #fff9ed;
}
td {
height: 100%;
font-size: 12px;
text-align: center;
// font-weight: 500;
padding: 0px;
border: 1px solid #f7f7f7;
border-top: none;
border-right: none;
box-sizing: border-box;
&:last-child {
border-right: 1px solid #f7f7f7;
}
}
}
}
}
// 表格元素
tr {
width: fit-content;
white-space: normal;
display: flex;
.td {
display: block;
display: flex;
justify-content: center;
align-items: center;
height: 35px;
color: #262626;
text-align: center;
box-sizing: border-box;
}
.seller_name {
width: 80px;
box-sizing: border-box;
}
.seller_phone,
.one_branch,
.two_branch {
width: 84px;
text-align: center;
box-sizing: border-box;
}
.total_uv,
.total_time,
.add_uv {
width: 64px;
text-align: center;
box-sizing: border-box;
}
.add_time {
width: 71px;
text-align: center;
box-sizing: border-box;
}
}
}
3、js实现表头、首列滚动
scrollFn (event) {
const col = document.getElementById('columnHeader-table')
col.style.top = -event.target.scrollTop + 'px'
const row = document.getElementById('rowHeader-table')
row.style.left = -event.target.scrollLeft + 'px'
},
4、遇到的bug调整
bug1:ios橡皮筋效果
解决方案:处理ios滚动的橡皮筋效果_多多的小宝贝的博客-CSDN博客
bug2:ios中纵向滚动、横向滚动不独立(横向滑动的同时,纵向会轻微滚动,纵向滑动的同时,横向会轻微滚动)
解决方案:禁用ios的自身滚动,利用代码实现滚动效果(但是滚动会没有浏览器滚动那么流畅丝滑,如果小伙伴们有更好的解决方案~可以一起讨论呐)
async mounted () {
if (/(iPhone|iPad|iPod)/i.test(navigator.userAgent)) {
console.log('是iOS设备')
// 阻止默认的处理方式(阻止下拉滑动的效果)
// passive 参数不能省略,用来兼容ios和android
const tableBody = document.getElementById('tableBody')
// 开始滑动的
let startPos, endPos, isScrolling, scrollTime
tableBody.addEventListener('touchstart', function (e) {
var touch = e.targetTouches[0] // touches数组对象获得屏幕上所有的touch,取第一个touch
// 开始滑动的时间戳
scrollTime = new Date().getTime()
startPos = { x: touch.pageX, y: touch.pageY, time: +new Date() } // 取第一个touch的坐标值
if (tableBody.offsetHeight > tableBody.offsetWidth) {
e.preventDefault()
}
}, { passive: false })
// 触摸移动
tableBody.addEventListener('touchmove', function (e) {
var touch = e.targetTouches[0]
endPos = { x: touch.pageX - startPos.x, y: touch.pageY - startPos.y }
isScrolling = Math.abs(endPos.x) < Math.abs(endPos.y) ? 1 : 0 // isScrolling为1时,表示纵向滑动,0为横向滑动
if (isScrolling == 0) { // 横向
// 横向滚动纵向不变
const time = (new Date().getTime() - scrollTime) / 1000
const speed = Math.abs(endPos.x) / time
// 判断左滑还是右滑,在左端就禁止左滑
if (endPos.x > 0 && tableBody.scrollLeft == 0 && endPos.x < startPos.x) { // 右滑
console.log('左滑')
e.preventDefault()
} else {
console.log('endPos.x ', endPos.x)
if (endPos.x < 0) {
tableBody.scrollTo({ left: `${tableBody.scrollLeft + speed * 0.7}`, behavior: 'smooth' })
} else {
tableBody.scrollTo({ left: `${tableBody.scrollLeft - speed * 0.7}`, behavior: 'smooth' })
}
const row = document.getElementById('rowHeader-table') // 表头
row.style.left = -tableBody.scrollLeft + 'px'
}
}
if (isScrolling == 1) { // 纵向
const time = (new Date().getTime() - scrollTime) / 1000
const speed = Math.abs(endPos.y) / time
console.log('speed', speed)
// console.log('hh_endPos.y', endPos.y) // 上滑<0,下滑》0
if (tableBody.scrollTop == 0 && endPos.y > 0) {
e.preventDefault()
} else {
// 纵向滚动横向不变
if (endPos.y < 0) {
tableBody.scrollTo({ top: `${tableBody.scrollTop + speed * 0.8}`, behavior: 'smooth' })
} else {
tableBody.scrollTo({ top: `${tableBody.scrollTop - speed * 0.8}`, behavior: 'smooth' })
}
const col = document.getElementById('columnHeader-table')// 首列
col.style.top = -tableBody.scrollTop + 'px'
}
}
}, { passive: false })
}
},