在小程序的开发中,不可避免会出现上下左右拖动表格的类似需求,下面将把这个简单实现一下
其中主要使用到了overflow: scroll;
来使得横向和纵向可以滚动,并且使用负边距 + 父容器截断
的方法来同时隐藏横向和纵向滚动条,从而实现该效果。
负边距 + 父容器截断
主要思路:
- 父容器:设置
overflow: hidden
截断滚动条。 - 子容器:
通过通过calc(100% + 滚动条宽度)
扩大尺寸,补偿滚动条占用的空间。
设置overflow: scroll
允许内容滚动。
用padding-right
和padding-bottom
补偿滚动条宽度,避免内容被遮挡。
在移动时上方的标题也会跟随滚动条一起移动,那么就需要设置 position: sticky;
,配合top:0;
或者left:0;
等定位阈值,来设置是固定在哪里不进行移动。
position: sticky;
是css中的一个定位属性,用于实现"粘性定位"的效果。作用类似于position:relative;
和position:fixed;
的结合体:元素在滚动到特定阈值前表现为相对定位(relative
),到达阈值后表现为固定定位(fixed
),从而始终可见。元素会停留在父容器或视口的指定位置(如顶部),直到父容器滚动结束。
该属性依赖于两个条件:
- 必须指定至少一个定位阈值(如
top:10px;
、bottom:0;
等) - 父容器不能有
overflow:hidden;
(否则失效)
javascript
<template lang="">
<view class="box">
<view class="placeBox">
<!-- 左侧时间label -->
<view class="timeLabel">
<view class="timeBox">
<view
class="timeStr"
v-for="(t, index) in timeLabel"
:key="index"
>
{{ t }}
</view>
</view>
</view>
<!-- 右侧内容区域 -->
<view class="contentBox">
<!-- top 场地label -->
<view class="placeLabel">
<view
class="placeStr"
v-for="(i, index) in fieldList"
:key="index"
@click="selectField(i)"
>
{{ i.stationname }}
</view>
</view>
<!-- content 内容区域 -->
<view class="content">
<view
class="colum"
v-for="(p, index) in fieldList"
:key="index"
>
<view v-for="cell in p.weekarr" :key="cell.hour">
<view class="cell">{{ cell.hour }}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const fieldList = ref([
{
stationname: '周一',
weekarr: [
{
hour: '10:00',
status: 0,
explain: 0,
},
{
hour: '11:00',
status: 0,
explain: 0,
},
],
},
{
stationname: '周二',
weekarr: [
{
hour: '10:00',
status: 0,
explain: 0,
},
{
hour: '11:00',
status: 0,
explain: 0,
},
],
},
{
stationname: '周三',
weekarr: [
{
hour: '10:00',
status: 0,
explain: 0,
},
{
hour: '11:00',
status: 0,
explain: 0,
},
],
},
{
stationname: '周四',
weekarr: [
{
hour: '10:00',
status: 0,
explain: 0,
},
{
hour: '11:00',
status: 0,
explain: 0,
},
],
},
{
stationname: '周五',
weekarr: [
{
hour: '10:00',
status: 0,
explain: 0,
},
{
hour: '11:00',
status: 0,
explain: 0,
},
],
},
{
stationname: '周六',
weekarr: [
{
hour: '10:00',
status: 0,
explain: 0,
},
{
hour: '11:00',
status: 0,
explain: 0,
},
],
},
{
stationname: '周日',
weekarr: [
{
hour: '10:00',
status: 0,
explain: 0,
},
{
hour: '11:00',
status: 0,
explain: 0,
},
],
},
])
const timeLabel = ref(['1号', '2号', '3号', '4号', '5号', '6号', '7号'])
</script>
<style lang="scss" scoped>
.box {
width: 600rpx;
height: 300rpx;
overflow: hidden;
.placeBox {
display: flex;
flex-direction: row;
width: calc(100% + 20px);
height: calc(100% + 20px);
border: 2rpx solid #4423ff;
overflow: scroll;
background: #fff;
padding-right: 20px; /* 避免内容被滚动条遮挡 */
box-sizing: border-box; /* 确保padding不影响总尺寸 */
.timeLabel {
padding-top: 52rpx;
position: sticky;
left: 0;
background: #fff;
.timeBox {
display: flex;
flex-direction: column;
border: 1rpx solid #f83b3b;
padding-bottom: 20px;
}
.timeStr {
width: 100rpx;
height: 50rpx;
text-align: center;
line-height: 50rpx;
}
}
.contentBox {
.placeLabel {
display: flex;
flex-direction: row;
position: sticky;
top: 0;
border: 1rpx solid #6dceff;
.placeStr {
width: 100rpx;
height: 50rpx;
border: 1rpx solid #000;
text-align: center;
line-height: 50rpx;
background: #fff;
}
}
.content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
background: #ccc;
.colum {
.cell {
width: 100rpx;
height: 50rpx;
border: 1rpx solid #000;
}
}
}
}
}
}
</style>