uni-app左右列表同步高亮滚动

最近在做点单小程序,其中左边是一级菜单,右边是商品列表,其中需求为左边点击高亮后,右边商品列表要滑动至相应的可视区域,同时右边商品列表滚动,左边的一级菜单可跟着可是区域的分类改变而高亮改变

最终运用到了uni-app中的额scroll-view组件,通过监听滚动和计算top值的方法,达到效果,demo代码如下:

<template>
    <view>
        <view class="flex scroll-contain">
            <scroll-view style="width:30%" class="left-scroll border-right" :scroll-top="leftScrollTop" scroll-y>
                <view class="left-nav" :class="{'active': activeIndex == i}" v-for="i in 50" :key="i"
                    @click="changeCate(i)">{{i}}</view>
            </scroll-view>

            <!-- #ifdef MP-WEIXIN -->
            <scroll-view style="width:70%" class="right-scroll" :scroll-top="rightScrollTop" @scroll="onRightScroll"
                scroll-y scroll-with-animation>
                <!-- #endif -->
                <!-- #ifdef MP-ALIPAY -->
                <scroll-view style="width:70%" class="right-scroll" :scroll-top="rightScrollTop" @scroll="onRightScroll"
                    scroll-y scroll-with-animation scroll-animation-duration=200>
                    <!-- #endif -->
                    <view class="right-nav" v-for="(item,index) in 50" :key="index">
                        <view class="sticky">{{'category'+item}}</view>
                        <view v-for="(item2 ,index2) in 10" :key="index2">
                            <text>{{'item'+item2}}</text>
                        </view>
                    </view>
                </scroll-view>
        </view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                containHeight: 0, // 滚动盒子的总高度
                activeIndex: 0, // 左边当前菜单项的索引
                leftDomsTop: [],
                rightDomsTop: [],
                leftScrollTop: 0,
                rightScrollTop: 0,
            }
        },
        onReady() {
            const query = uni.createSelectorQuery().in(this);
            query.selectAll('.scroll-contain').boundingClientRect(data => {
                this.containHeight = data[0].height
            }).exec();
            query.selectAll('.left-nav').boundingClientRect(data => {
                this.leftDomsTop = data.map(v => v.top)
            }).exec();
            query.selectAll('.right-nav').boundingClientRect(data => {
                this.rightDomsTop = data.map(v => v.top - 30)
            }).exec();
        },
        methods: {
            // 点击左边导航栏
            changeCate(index) {
                this.activeIndex = index
                this.rightScrollTop = this.rightDomsTop[index]
            },
            // 右侧滚动
            onRightScroll(e) {
                // 匹配当前scrollTop所处的索引
                this.rightDomsTop.forEach((v, k) => {
                    if (v < e.detail.scrollTop + 3) {
                        this.activeIndex = k
                        return false
                    }
                })
                const targetScrollTop = this.leftDomsTop[this.activeIndex] - this.containHeight * 0.5
                const maxScrollTop = this.leftDomsTop[this.leftDomsTop.length - 1] - this.containHeight + (this
                    .leftDomsTop[this.leftDomsTop.length - 1] - this.leftDomsTop[this.leftDomsTop.length - 2])
                if (targetScrollTop == this.leftScrollTop) return
                this.leftScrollTop = Math.min(targetScrollTop, maxScrollTop)
            }
        },
    }
</script>

<style lang="scss">
    .scroll-contain {
        height: 80vh;
    }

    .active {
        background-color: #09f;
    }

    .flex {
        display: flex;
    }

    .sticky {
        position: sticky;
        top: 0;
        background-color: #fff;
    }
</style>

 

posted @ 2022-08-22 17:45  ~逍遥★星辰~  阅读(273)  评论(0编辑  收藏  举报