在小程序中实现上下左右拖动表格

在小程序的开发中,不可避免会出现上下左右拖动表格的类似需求,下面将把这个简单实现一下

其中主要使用到了overflow: scroll;来使得横向和纵向可以滚动,并且使用负边距 + 父容器截断的方法来同时隐藏横向和纵向滚动条,从而实现该效果。

负边距 + 父容器截断主要思路:

  1. 父容器:设置 overflow: hidden 截断滚动条。
  2. 子容器:
    通过通过 calc(100% + 滚动条宽度) 扩大尺寸,补偿滚动条占用的空间。
    设置 overflow: scroll 允许内容滚动。
    padding-rightpadding-bottom 补偿滚动条宽度,避免内容被遮挡。

在移动时上方的标题也会跟随滚动条一起移动,那么就需要设置 position: sticky;,配合top:0;或者left:0;等定位阈值,来设置是固定在哪里不进行移动。
position: sticky;是css中的一个定位属性,用于实现"粘性定位"的效果。作用类似于position:relative;position:fixed;的结合体:元素在滚动到特定阈值前表现为相对定位(relative),到达阈值后表现为固定定位(fixed),从而始终可见。元素会停留在父容器或视口的指定位置(如顶部),直到父容器滚动结束。

该属性依赖于两个条件:

  1. 必须指定至少一个定位阈值(如top:10px;bottom:0;等)
  2. 父容器不能有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>
相关推荐
帅次7 分钟前
Flutter动画全解析:从AnimatedContainer到AnimationController的完整指南
android·flutter·ios·小程序·kotlin·android studio·iphone
dreamer2923 小时前
[特殊字符]️ 微信小程序反编译实战教程
微信小程序·小程序
云起SAAS9 小时前
H5小游戏封装流量主小程序壳开源
小程序·h5小游戏封装流量主小程序
從南走到北19 小时前
设备巡检系统小程序ThinkPHP+UniApp
微信小程序·小程序·uni-app·微信公众平台
weixin_lynhgworld21 小时前
同城社交系统开发,解锁城市生活新玩法
小程序·生活·搭子
雨中的风铃子1 天前
taro小程序如何实现新用户引导功能?
小程序·taro
云起SAAS1 天前
密室出逃消消乐小游戏微信流量主小程序开源
小程序·密室出逃消消乐小游戏微信流
前端早间课1 天前
微信小程序获取指定元素,滚动页面到指定位置
微信小程序·小程序
汇匠源1 天前
Java 零工市场小程序 | 灵活就业平台 | 智能匹配 | 日结薪系统 | 用工一站式解决方案
java·小程序