Vue 列是否固定在左侧

vue table 固定列
  • 利用css position定位position: sticky属性实现;
  • 利用JS addEventListener监听事件控制表头与tbody同时滑动

父组件使用

 <list
    :tableData="manager"
    :tableConfig="mngInfo"
    id="manager"
></list>

manager:[],//返回数据
    // 表格数据
    mngInfo:[
            {
            width: 140,         // 表格宽度
            percent: false,     // 百分单位
            isSort: false,      // 是否排序
            sortKey: '',        // 排序字段
            label:'表格一',       // 表头 名称
            left: 0,            // 距左距离
            color: '#fff',      // 文字颜色
            showSort: true,    // 展示左侧序号
            setData: false,     // 处理单位
            key: '',        // k名
            sizeKey: '',        // 是否根据大小判断颜色 排序字段
            unit: '',           // 单位
            stock: false,       // 是否是  股票名称
            codeKey: '',   //股票代码key
            nameKey: '', // 股票名称 key
            toKLine: false,     // 是否跳转k线
        },
        {
            width: 140,
            percent: false,
            isSort: false,
            sortKey: '',
            label:'表格二',
            left: '140',
            color: '#fff',
            showSort: false,
            setData: false,
            key: 'indiName',
            sizeKey: '',
            unit: '',
            codeKey: '', //股票代码key
            nameKey: '',  // 股票名称 key
            toKLine: 'false',  // 是否跳转k线
            stockType: '', // 股票后缀 key
        },
        {
            width: 140,
            percent: false,
            isSort: false,
            sortKey: '',
            label:'表格三',
            left: '',
            color: '#fff',
            showSort: false,
            setData: false,
            key: 'gender',
            sizeKey: '',
            unit: '',
        },
        {
            width: 140,
            percent: false,
            isSort: false,
            sortKey: '',
            label:'表格四',
            left: '',
            color: '#fff',
            showSort: false,
            setData: false,

            key: 'birthYear',
            sizeKey: '',
            unit: '',
        },
       
    ],
    
import list from './list';
components: {list},

表格组件 list.vue

<template>
    <div class="list-content" :id="id">
        <div class="t-head" ref="tHead">
            <span
                v-for="(item,k) in tableConfig"
                :key="k"
                :class="['head']"
                :style="{width: torem(item.width),left: torem(item.left)}"
                @click.stop=""
            >
                <template >
                    <p v-html="item.label"></p>
                </template>
            </span>
        </div>
        <div class="t-data" ref="tData" id="tData">
            <div class="t-tr" v-for="(item,i) in tableData" :key="i" :style="{width: torem(allWidth)}">
                <span
                    v-for="(data,k) in tableConfig"
                    :key="k"
                    :class="['td',data.stock?'stock': '', color(item[data.sizeKey])]"
                    :style="{width: torem(data.width),left: torem(data.left),'font-size':torem(data.fontSize),'line-height':torem(data.lineHeight),'text-align':data.textAlign}"
                    @click="data.toKLine?toKLine(item):''"
                >
                    <template v-if="data.showSort">
                        {{i+1}}
                    </template>
                    <template v-else-if="data.setData">
                        {{item[data.key]}}
                    </template>
                    <template v-else>
                        {{item[data.key] || '-'}}{{data.unit}}
                    </template>
                </span>  
            </div>
            <div class="no-data" v-show="tableData.length<1">暂无数据</div>
        </div>
    </div>
</template>
 props: {
        tableData: {
            default: ()=> []
        },
        tableConfig: {
             default: ()=> []
        },
        id: {
            type: String,
            default: 'listContent'
        },
   },
computed: {
    //动态计算表格的宽度
        allWidth(){
            let width = 0;
            this.tableConfig.forEach(item=>{
                width+=item.width
            });
            return width + this.tableConfig.length;
        }
    },
    methods: {
        // 修改 vxe-table 中的滑动容器行为
        bindTouchEvents () {
            const element = document.getElementById(this.id);
            if (element) {
                element.addEventListener(
                'touchstart',
                event => {
                    this.touchX = event.changedTouches[0].clientX;
                    this.touchY = event.changedTouches[0].clientY;
                },
                true
                )
                element.addEventListener(
                'touchmove',
                event => {
                    event.preventDefault();
                    let html = document.getElementById('f10');//处理
                    // 计算手指偏移量
                    const offsetX = event.changedTouches[0].clientX - this.touchX
                    const offsetY = event.changedTouches[0].clientY - this.touchY
                    this.$refs.tHead.scrollLeft = this.$refs.tHead.scrollLeft - offsetX;
                    this.$refs.tData.scrollLeft = this.$refs.tData.scrollLeft - offsetX;
                    this.$parent.$el.scrollTop = this.$parent.$el.scrollTop -offsetY;
                    html.scrollTop = html.scrollTop - offsetY;
                    this.touchX = event.changedTouches[0].clientX
                    this.touchY = event.changedTouches[0].clientY
                },
                true
                )
                element.addEventListener(
                'touchend',
                event => {
                    this.touchX = event.changedTouches[0].clientX
                    this.touchY = event.changedTouches[0].clientY
                },
                true
                )
            } else {
                console.warn('未获取到表格元素')
            }
        }
   }  
<style lang="scss" scoped>
.list-content {
    // 表头
    .t-head{
        white-space: nowrap;
        overflow-x: auto;
        border-bottom: 1px solid #DEDEDE;
        border-right: none;
        font-size: 0;
        & >span {
            height: 48px;
            border-right: 1px solid #DEDEDE;
            font-size: 13px;
            line-height: 18px;
            color: #666666;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            z-index: 0;
            background: #F8F8F8;
            vertical-align: top;
            text-align: center;
            &:nth-child(1){
                position: -webkit-sticky;//固定第一列
                position: sticky;
                left: 0;
                z-index: 2;
            }
            &:nth-child(2){
                position: -webkit-sticky;//固定第二列
                position: sticky;
                z-index: 1;
            }
            &.sort{//排序
                .icon-con{
                    display: flex;
                    flex-direction: column;
                    align-items: flex-start;
                    justify-content: center;
                     transform: scale(0.6);
                    .icon {
                        font-size: 12px;
                        line-height: 12px;
                    }
                }
                &.act.desc{
                    .icon-con{
                        .icon{
                            &:nth-child(2){
                                color: #EA2827;
                            }
                        }
                    }
                }
                &.act.asc{
                    .icon-con{
                        .icon{
                            &:nth-child(1){
                                color: #EA2827;
                            }
                        }
                    }
                }
            }
        }
    }
    // table体
    .t-data{
        overflow-x: auto;
        box-sizing: border-box;
        font-size: 0;
        max-width: 100vw;
        -webkit-overflow-scrolling: touch;
        div{
            white-space: nowrap;
            border-bottom: 1px solid #DEDEDE;
            display: flex;
            align-items: stretch;
            //隔行变色 todo end
            & >span {
                display: inline-block;
                box-sizing: border-box;
                margin-right: 1px;
                font-size: 17px;
                color: #333333;
                display: inline-flex;
                align-items: center;
                justify-content: center;
                z-index: 0;
                padding: 8px 5px;
                line-height: 21px;
                white-space: normal;
                &:nth-child(1){
                    position: -webkit-sticky;//固定第一列
                    position: sticky;
                    left: 0;
                    z-index: 2;
                }
                &:nth-child(2){
                    position: -webkit-sticky;//固定第二列
                    position: sticky;
                    z-index: 1;
                }
            }
        }
    }
}
</style>

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值