vue移动端表格吸顶、行自适应高度、列左侧固定悬浮

简介

1.表头吸顶效果
2.左侧列固定,右侧滑动,表头跟随内容滑动
3.行高自适应

番外

最近上海疫情,居家办公一月多了,愿阴霾散去。最近网上在正常得市民抱怨中,有很多别有用心之人,数典忘祖,造谣生事,其心可诛。

如图所示

在这里插入图片描述

源码(复制另存txt,修改.html直接运行)
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="referrer" content="no-referrer" />
    <meta name="viewport"
        content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no, viewport-fit=cover" />
    <title>vue移动端表格吸顶、列自适应高度、列左侧固定悬浮</title>
    <!-- 引入样式 -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <style>
        /* 页面所需样式 */
        html,
        body,
        #app {
            width: 100%;
        }

        .cardBox {
            border-radius: 8px;
        }

        .tableBox {
            border: 1px solid #EBECF0;
            border-radius: 4px;
            color: #494949;
        }

        .right {
            overflow-x: auto;
        }

        .tableHead {
            background: #E8EDFF;
            height: 32px;
            line-height: 32px;
        }

        .borderBottom {
            border-bottom: 1px solid #EBECF0;
        }

        .width100 {
            width: 100px;
        }

        .width70 {
            width: 70px;
        }

        .width40 {
            width: 40px;
        }

        .colorff {
            color: #ff0000;
        }

        .color00 {
            color: #00d7a2;
        }

        .fw500 {
            font-weight: 500
        }

        .icon {
            width: 20px;
            height: 20px;
            transition: all 0.1s;
        }

        .icon-active {
            width: 20px;
            height: 20px;
            color: yellow;
            transform: rotate(180deg);
            transition: all 0.1s;
        }
    </style>
</head>

<body style="background: #eee;">
    <div id="app" class="pt10">
        <div class="cardBox pl10 pr10 pt15 pb15 borBox bgf ml12 mr12 mb12 fz16">

            <div class="fz14 fw color3 pmps mb12 ml12">vue移动端表格吸顶、<br />列自适应高度、<br />列左侧固定悬浮</div>
            <!-- 浮动头部 start -->
            <div class="tableBox flex w100" style="position: sticky;top:0px;z-index:5;border-radius: 4px 4px 0 0;">
                <!-- 左侧固定列 -->
                <div class="fz12 lh20 flex">
                    <div class="tl fw pmps tableHead pl10 borBox pr10" style="max-width:140px">游戏类型</div>
                    <div class="fw pmps tableHead borBox pr10 tl" style="width:80px">姓氏名谁</div>
                    <div class="fw pmps tableHead borBox pr10 tl" style="width:75px">中级技能</div>
                </div>
                <!-- 右侧滚动区域 -->
                <div class="txtno right flex1" @scroll="divScroll" ref="rightBoxHead">
                    <div class="flex fz12 pmps tr fw" style="width:max-content">
                        <div class="tableHead width40" style="line-height:15px;">指标<br />环比</div>
                        <div class="tableHead width70"><span class="fz12 color6 fbf">(千)</span></div>
                        <div class="tableHead width70">日环</div>
                        <div class="tableHead width70"><span class="fz12 color6 fbf">(千)</span></div>
                        <div class="tableHead width70">月环</div>
                        <div class="tableHead width70"><span class="fz12 color6 fbf">(千)</span></div>
                    </div>
                </div>
            </div>
            <!-- 浮动头部 end -->
            <div class="tableBox flex w100" style="border-radius: 0 0 4px 4px;">
                <!-- 左侧固定列 -->
                <div class="fz12 lh20 flex">
                    <div>
                        <div v-for="(item ,i) in typeList" :key="i" :style="{height:item.height}"
                            style="max-width:140px" class="prps pl10 borBox pr10 pt5 pb5"
                            :class="{borderBottom:i != typeList.length - 1}">{{item.businessPart}}</div>
                    </div>
                    <div>
                        <!-- 姓氏名谁 默认只有此列数据可能换行,其他列数据固定 -->
                        <!-- :ref="'leftRef'+i":style="{height:item.height}" 用来计算可能存在得换行数据高度/动态赋值 -->
                        <div v-for="(item ,i) in typeList" :key="i" :style="{height:item.height}" :ref="'leftRef'+i"
                            style="width:80px" class="prps borBox pt5 pb5 tl"
                            :class="{borderBottom:i != typeList.length - 1}">{{item.businessLine}}</div>
                    </div>
                    <div>
                        <div v-for="(item ,i) in typeList" :key="i" :style="{height:item.height}" style="width:75px"
                            class="prps borBox pt5 pb5 tl" :class="{borderBottom:i != typeList.length - 1}">
                            {{item.childBusiness}}</div>
                    </div>
                </div>
                <!-- 右侧滚动区域 -->
                <div class="txtno right flex1" @scroll="divScroll" ref="rightBoxContent">
                    <div class="flex fz14 pmps tr fw lh20" v-for="(item ,i) in typeList" :key="i"
                        :style="{height:item.height}" style="width:max-content">
                        <div class="width40 pt5 pb5 borBox" :style="{height:item.height}"
                            :class="[i == typeList.length - 1?'':'borderBottom']">
                            <span v-if="parseFloat(item.indicatorRate)"
                                :class="[parseFloat(item.indicatorRate) > 0? 'colorff':'color00']">{{item.indicatorRate}}</span>
                            <span v-else>0</span>
                        </div>
                        <div class="width70 pt5 pb5 borBox" :style="{height:item.height}"
                            :class="{borderBottom:i != typeList.length - 1}">{{item.dayValue}}</div>
                        <div class="width70 pt5 pb5 borBox" :style="{height:item.height}"
                            :class="[i == typeList.length - 1?'':'borderBottom']">
                            <span v-if="parseFloat(item.dayRate)"
                                :class="[parseFloat(item.dayRate) > 0? 'colorff':'color00']">{{item.dayRate}}</span>
                            <span v-else>0</span>
                        </div>
                        <div class="width70 pt5 pb5 borBox" :style="{height:item.height}"
                            :class="{borderBottom:i != typeList.length - 1}">{{item.monthValue}}</div>
                        <div class="width70 pt5 pb5 borBox" :style="{height:item.height}"
                            :class="[i == typeList.length - 1?'':'borderBottom']">
                            <span v-if="parseFloat(item.monthRate)"
                                :class="[parseFloat(item.monthRate) > 0? 'colorff':'color00']">{{item.monthRate}}</span>
                            <span v-else>0</span>
                        </div>
                        <div class="width70 pt5 pb5 borBox" :style="{height:item.height}"
                            :class="{borderBottom:i != typeList.length - 1}">{{item.yearValue}}</div>
                    </div>
                </div>
            </div>
            <div class="w100 pt5 flex justc alic" v-if='typeList.length != 0' @click="showMore">
                <span class="fz12 color6 lh20">{{isActiveMore?'收起':'查看更多'}}</span>
                <img style="pointer-events:auto"
                    src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABdklEQVRoQ+2WP2rDMBjFJWzPHQs5QE8QumfJRWywlvYKTa7QLDLYF8mSvfQEPUCgY2bbuAgsCAY51veHYvi82t/T+70nCWu18kev3L8SgP9uUBqQBpAJyBZCBogelwbQESIFpAFkgOhxaQAdIVJAGpgLsKqqD/e+LMsjMujgOFsDo/nDuPKBC4IFYGLep8cCQQ4QMM8GQQrwwDwLBBlAwPxtdP00OYVk24kEIGQ+SZK9M973/VkpxQKBBpgzXxTFlwOo6/qVCwIFsMS83zpcEGCAGPOcECAAiHkuiGgAjHkOiCgAa+2b1vpzciXe3G3jD+zSf57QmRiG4d0Yc1qqEwXQNM2m67qLUuplXABkfqaJnzRNd3meX1kAnOgdxDMk+amxuyZ+Y807ragG/OIOom3bjTHme2lSc99Za7dZll1jkvd6IAAK01QaAkCVJFRHGoAmRzUnDVAlCdWRBqDJUc1JA1RJQnWkAWhyVHPSAFWSUJ3VN/AHyEyuMZ39T8kAAAAASUVORK5CYII="
                    alt="icon" :class="[isActiveMore?'icon':'icon-active','inline']" />
            </div>
            <div class="tl color6 fz12 mt10 ml12">疫情在家三十多天了,好家伙,我想出去玩!</div>
            <div v-if='typeList.length == 0' class="tc color6 fz14 mt10">暂无数据</div>

        </div>
    </div>
</body>

<script src="https://lib.baomitu.com/vue/2.6.14/vue.js"></script>
<!-- 引入组件库 -->
<!-- <script src="https://unpkg.com/element-ui/lib/index.js"></script> -->
<!-- 引入 echart -->
<!-- <script src="https://lib.baomitu.com/echarts/5.2.0/echarts.common.js"></script> -->

<script>
    let timer = ''
    new Vue({
        el: '#app',
        data() {
            return {
                typeAllList: [
                    {
                        businessLine: "蛮王",
                        businessPart: "英雄联盟",
                        childBusiness: "开大招",
                        dayRate: "-10.0%",
                        dayValue: "10.0",
                        indicatorRate: "0/1",
                        monthRate: "10.0%",
                        monthValue: "10.0",
                        order: 220,
                        yearValue: "10.0",
                    },
                    {
                        businessLine: "亚索",
                        businessPart: "英雄联盟",
                        childBusiness: "疾风剑豪",
                        dayRate: "10.0%",
                        dayValue: "220.0",
                        indicatorRate: "0/1",
                        monthRate: "10.0%",
                        monthValue: "330.0",
                        order: 4440,
                        yearValue: "20.0",
                    },
                    {
                        businessLine: "EZ说他最帅可以换行",
                        businessPart: "英雄联盟",
                        childBusiness: "星传说",
                        dayRate: "60.0%",
                        dayValue: "60.0",
                        indicatorRate: "0/1",
                        monthRate: "60.0%",
                        monthValue: "60.0",
                        order: 660,
                        yearValue: "60.0",
                    },
                ],
                typeList: [],
                isActiveMore: false,
            }
        },
        created() {
            // 初始化数据
            Array.from({ length: 30 }).map(() => {
                this.typeAllList.push({
                    businessLine: "火影忍者",
                    businessPart: "木叶村",
                    childBusiness: "影分身",
                    dayRate: "160.0%",
                    dayValue: "160.0",
                    indicatorRate: "0/1",
                    monthRate: "160.0%",
                    monthValue: "160.0",
                    order: 1660,
                    yearValue: "160.0",
                })
            })
            // 根据激活项,是否展示更多数据,默认展示8条
            if (this.isActiveMore) {
                this.typeList = this.typeAllList
            } else {
                this.typeList = this.typeAllList.length > 0 ? this.typeAllList.slice(0, 8) : []
            }
        },
        mounted() {
            // 延迟获取每一行高度
            setTimeout(() => {
                this.$nextTick(() => {
                    this.typeList.map((item, i) => {
                        this.getHeight(i)//动态读取每一项高度
                    })
                    this.typeList = [...this.typeList]
                })
            }, 500)
        },
        methods: {
            //展示更多
            showMore() {
                this.isActiveMore = !this.isActiveMore
                if (this.isActiveMore) {
                    this.typeList = this.typeAllList
                } else {
                    this.typeList = this.typeAllList.length > 0 ? this.typeAllList.slice(0, 8) : []
                }
                this.$nextTick(() => {
                    this.typeList.map((item, i) => {
                        this.getHeight(i)
                    })
                    this.typeList = [...this.typeList]
                })
            },
            //滚动条
            divScroll(event) {
                if (timer) {
                    window.clearTimeout(timer)
                    timer = ''
                }
                timer = window.setTimeout(() => {
                    this.$refs.rightBoxContent.scrollLeft = event.target.scrollLeft
                    this.$refs.rightBoxHead.scrollLeft = event.target.scrollLeft
                }, 10)
            },
            //动态获取高度
            getHeight(i) {
                // console.dir(this.$refs['leftRef2'][0])
                this.typeList[i].height = this.$refs['leftRef' + i][0].offsetHeight + 'px'
            }
        }
    })
</script>

<style>
    @charset "utf-8";

    /* CSS Document 公共样式表*/
    html,
    body {
        height: 100%;
        width: 100%;
        word-wrap: break-word;
    }

    .w50 {
        width: 50%;
    }

    .w100 {
        width: 100%;
    }

    * {
        margin: 0;
        padding: 0;
        outline: none;
    }

    .tc {
        text-align: center
    }

    .tl {
        text-align: left;
    }

    .tr {
        text-align: right
    }

    .vm {
        vertical-align: middle;
    }

    .fl {
        float: left;
    }

    .fr {
        float: right;
    }

    .fz26 {
        font-size: 26px;
    }

    .fz25 {
        font-size: 25px;
    }

    .fz24 {
        font-size: 24px;
    }

    .fz22 {
        font-size: 22px;
    }

    .fz20 {
        font-size: 20px;
    }

    .fz18 {
        font-size: 18px;
    }

    .fz16 {
        font-size: 16px;
    }

    .fz14 {
        font-size: 14px;
    }

    .fz12 {
        font-size: 12px;
    }

    .fz11 {
        font-size: 11px;
        -webkit-transform: scale(0.85);
        transform: scale(0.85);
        display: inline-block;
    }

    .fz10 {
        font-size: 10px;
        -webkit-transform: scale(0.8);
        transform: scale(0.8);
        display: inline-block;
    }

    .fw {
        font-weight: 600;
    }

    .fw4 {
        font-weight: 400;
    }

    .fwB {
        font-weight: bold;
    }

    .mr5 {
        margin-right: 5px
    }

    .mr10 {
        margin-right: 10px
    }

    .mr12 {
        margin-right: 12px
    }

    .mr15 {
        margin-right: 15px
    }

    .mr20 {
        margin-right: 20px
    }

    .ml5 {
        margin-left: 5px;
    }

    .ml10 {
        margin-left: 10px;
    }

    .ml12 {
        margin-left: 12px;
    }

    .ml15 {
        margin-left: 15px;
    }

    .ml20 {
        margin-left: 20px;
    }

    .mt40 {
        margin-top: 40px;
    }

    .mt20 {
        margin-top: 20px;
    }

    .mt15 {
        margin-top: 15px;
    }

    .mt12 {
        margin-top: 12px;
    }

    .mt10 {
        margin-top: 10px;
    }

    .mt5 {
        margin-top: 5px;
    }

    .mt3 {
        margin-top: 3px;
    }

    .mt7 {
        margin-top: 7px;
    }

    .mb5 {
        margin-bottom: 5px;
    }

    .mb10 {
        margin-bottom: 10px;
    }

    .mb12 {
        margin-bottom: 12px;
    }

    .mb15 {
        margin-bottom: 15px;
    }

    .mb20 {
        margin-bottom: 20px;
    }

    .pt5 {
        padding-top: 5px;
    }

    .pt10 {
        padding-top: 10px;
    }

    .pt12 {
        padding-top: 12px;
    }

    .pt15 {
        padding-top: 15px;
    }

    .pt20 {
        padding-top: 20px;
    }

    .pb5 {
        padding-bottom: 5px;
    }

    .pb10 {
        padding-bottom: 10px;
    }

    .pb12 {
        padding-bottom: 12px;
    }

    .pb15 {
        padding-bottom: 15px;
    }

    .pb20 {
        padding-bottom: 20px;
    }

    .pl5 {
        padding-left: 5px;
    }

    .pl10 {
        padding-left: 10px;
    }

    .pl12 {
        padding-left: 12px;
    }

    .pl15 {
        padding-left: 15px;
    }

    .pl20 {
        padding-left: 20px;
    }

    .pr5 {
        padding-right: 5px;
    }

    .pr10 {
        padding-right: 10px;
    }

    .pr12 {
        padding-right: 12px;
    }

    .pr15 {
        padding-right: 15px;
    }

    .pr20 {
        padding-right: 20px;
    }

    .bgf {
        background: #fff;
    }

    .bgea {
        background: #EAEAEA;
    }

    .bgF3 {
        background: #5377F3;
    }

    .bg48 {
        background: #F2B448;
    }

    .bgA2 {
        background: #00D7A2;
    }

    .bgF4 {
        background: #FFFBF4;
    }

    .bgFb {
        background: #EEFFFB;
    }

    .bgs {
        box-shadow: 0px 0px 15px #eee;
    }


    .colorF {
        color: #fff;
    }

    .color3 {
        color: #333;
    }

    .color6 {
        color: #666;
    }

    .color9 {
        color: #999;
    }

    .color49 {
        color: #494949;
    }

    .color80 {
        color: #808080;
    }

    .colorA5 {
        color: #A5A5A5
    }

    .colorb {
        color: blue
    }

    .colorF3 {
        color: #5377F3;
    }

    .color48 {
        color: #F2B448;
    }

    .colorA2 {
        color: #00D7A2;
    }

    .color00 {
        color: #FF0000
    }

    .color26 {
        color: #FFA926;
    }


    .lh20 {
        line-height: 20px;
    }

    .lh22 {
        line-height: 22px;
    }

    .lh24 {
        line-height: 24px;
    }

    .lh30 {
        line-height: 30px;
    }

    .lh36 {
        line-height: 36px;
    }

    .lh40 {
        line-height: 40px;
    }

    .lh50 {
        line-height: 50px;
    }

    .lh60 {
        line-height: 60px;
    }

    .hide {
        display: none
    }

    .show {
        display: block
    }

    .inline {
        display: inline-block;
    }

    .indent2 {
        text-indent: 2em;
    }

    .txt2 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }

    .txt3 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 3;
        -webkit-box-orient: vertical;
    }

    .txtno {
        white-space: nowrap;
    }

    /*不换行*/
    .txtsa {
        text-align: justify;
        text-align-last: justify;
    }

    /*文字分散对齐*/
    .wn {
        white-space: nowrap;
    }

    .flex {
        display: flex;
    }

    .flex1 {
        flex: 1;
    }

    .colu {
        flex-direction: column;
    }

    .justc {
        justify-content: center;
    }

    .justs {
        justify-content: space-between
    }

    /*两端对齐*/
    .justsa {
        justify-content: space-around
    }

    /*分散对齐*/
    .juste {
        justify-content: flex-end;
    }

    .alic {
        align-items: center
    }

    .wrap {
        flex-wrap: wrap
    }

    .childEnd {
        align-self: flex-end;
    }

    .posAbs {
        position: absolute;
    }

    .posRel {
        position: relative;
    }

    .posFix {
        position: fixed;
    }

    .top0 {
        top: 0;
    }

    .bottom0 {
        bottom: 0;
    }

    .left0 {
        left: 0;
    }

    .right0 {
        right: 0;
    }

    .w100 {
        width: 100%
    }

    .h100 {
        height: 100%
    }

    .border0 {
        border: 0
    }

    .borBox {
        box-sizing: border-box;
    }

    .borderte0 {
        border-top: 1px solid #e0e0e0;
    }

    .borderbe0 {
        border-bottom: 1px solid #e0e0e0;
    }

    .borRad {
        border-radius: 5px;
    }

    .borRad50 {
        border-radius: 50%;
    }

    .over {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }

    .overH {
        overflow: hidden
    }

    .overS {
        overflow: scroll;
    }

    .clear {
        zoom: 1;
    }

    .clear:after {
        content: "\0020";
        display: block;
        height: 0;
        clear: both;
    }

    .mask {
        width: 100%;
        height: 100%;
        background: rgba(20, 20, 20, 0.5);
        position: fixed;
        z-index: 5;
        top: 0;
        left: 0;
    }

    .cursor {
        cursor: pointer;
    }

    .noClick {
        pointer-events: none;
    }

    li {
        list-style: none;
    }

    a {
        text-decoration: none;
        color: #555;
    }

    a:hover {
        color: #555;
    }

    img {
        display: block;
        vertical-align: middle;
    }

    a img,
    fieldset {
        border: 0;
    }

    i,
    em {
        font-style: normal
    }

    input,
    textarea,
    select {
        outline: none;
    }

    textarea {
        resize: none;
    }

    table {
        border-collapse: collapse;
    }

    [v-cloak] {
        display: none;
    }

    /* 公用字体 start */
    .psps {
        font-family: PingFangSC-Semibold, PingFang SC;
    }

    .pmps {
        font-family: PingFangSC-Medium, PingFang SC;
    }

    .fbf {
        font-family: FinFont-Bold, FinFont;
    }

    .prps {
        font-family: PingFangSC-Regular, PingFang SC;
    }

    /* 公用字体 end */
</style>

</html>
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘斩仙的笔记本

富贵险中求

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值