实现滚动文章内容到一定区域后,某个对应的tab按钮高亮显示

淳于凯
2023-12-01

实现滚动文章内容到一定区域后,某个对应的tab按钮高亮显示

场景:假设一个页面分为四个板块,每个板块为一个组件,顶部是四个tab按钮,点击哪个按钮页面就自动定位到对应的版块,且按钮要高亮,若用户自己滑动页面,滑动到哪个板块区域,对应的tab按钮也要高亮

<template>
    <scroll-view
        @scroll="scroll"
        @scrolltolower="onreachBottom"
        scroll-y
        style="width: 100%; height: 100%; overflow: hidden auto"
        id="scroll-view-id"
    >
        <view class="module-tabs">
            <view
                class="tabs-button"
                :class="{ active: menuIndex == item.hook }"
                v-for="(item, index) in tabsList"
                :key="index"
                @click="hookTo(item.hook)"
            >
                {{ item.name }}
            </view>
        </view>
        <view class="">
            <view>
                <news
                    ref="news"
                    :id="`${platClass}-news`"
                    :platform="platform"
                ></news>
            </view>
            <view>
                <using-manaual
                    ref="usingManaual"
                    :id="`${platClass}-manaual`"
                    :platform="platform"
                ></using-manaual>
            </view>
            <view>
                <learn-zone
                    ref="learnZone"
                    :id="`${platClass}-learn`"
                    :platform="platform"
                ></learn-zone>
            </view>
            <view>
                <video-learning
                    ref="videoLearning"
                    :id="`${platClass}-video`"
                    :platform="platform"
                ></video-learning>
            </view>
            <view style="height: 1px"></view>
        </view>
    </scroll-view>
</template>

<script>
import news from "../components/news.vue";
import usingManaual from "../components/usingManaual.vue";
import learnZone from "../components/learnZone.vue";
import videoLearning from "../components/videoLearning.vue";
export default {
    components: {
        news,
        usingManaual,
        learnZone,
        videoLearning,
    },
    props: {
        platform: {
            type: String,
            default: () => {
                return "";
            },
        },
        platClass: {
            type: String,
            default: () => {
                return "";
            },
        },
        tabsList: {
            type: Array,
            default: () => {
                return [];
            },
        },
        current: {
            type: Number,
            default: () => {
                return 0;
            },
        },
    },
    data() {
        return {
            scrollAy: 0,
            scrollBy: 0,
            scrollCy: 0,
            scrollDy: 0,
            scrollAx: 0,
            scrollBx: 0,
            scrollCx: 0,
            scrollDx: 0,
            menuIndex: "",
            viewHight: "",
            scrollFlag: false,
            scrollView: "",
            bottomFlag: false,
        };
    },
    mounted() {
        this.menuIndex = `${this.platClass}-news`;
    },
    methods: {
        onreachBottom(e) {
            let vm = this;

            console.log("222222222", e);
            vm.bottomFlag = true;
            console.log("-------vm.bottomFlag-222222-----", vm.bottomFlag);
        },
        getScrollHeight() {
            let vm = this;

            //getBoundingClientRect().y在这里不适用,固先注销掉
            // vm.scrollAy = document
            //  .querySelector(`#${vm.platClass}-news`)
            //  .getBoundingClientRect().y;
            // vm.scrollBy = document
            //  .querySelector(`#${vm.platClass}-manaual`)
            //  .getBoundingClientRect().y;
            // vm.scrollCy = document
            //  .querySelector(`#${vm.platClass}-learn`)
            //  .getBoundingClientRect().y;
            // vm.scrollDy = document
            //  .querySelector(`#${vm.platClass}-video`)
            //  .getBoundingClientRect().y;

            vm.scrollAx = document
                .querySelector(`#${vm.platClass}-news`)
                .getBoundingClientRect().x;
            vm.scrollBx = document
                .querySelector(`#${vm.platClass}-manaual`)
                .getBoundingClientRect().x;
            vm.scrollCx = document
                .querySelector(`#${vm.platClass}-learn`)
                .getBoundingClientRect().x;
            vm.scrollDx = document
                .querySelector(`#${vm.platClass}-video`)
                .getBoundingClientRect().x;
        },
        hookTo(name) {
            let vm = this;
            let hook = `#${name}`;

            let hookEl = document.querySelector(hook);
            //获取各个组件的最顶层父组件,只有最顶层父组件才是实现可滚动的元素
            let scrollEl = hookEl.parentNode.parentNode.parentNode.parentNode;
            let scrollAy = document.querySelector(
                `#${vm.platClass}-news`
            ).offsetHeight;
            let scrollBy = document.querySelector(
                `#${vm.platClass}-manaual`
            ).offsetHeight;
            let scrollCy = document.querySelector(
                `#${vm.platClass}-learn`
            ).offsetHeight;
            let scrollDy = document.querySelector(
                `#${vm.platClass}-video`
            ).offsetHeight;
            let clientHeight =
                document.querySelector("#scroll-view-id").offsetHeight;
            //由于scrollIntoView方法定位的位置精确度不高,固弃用该方法
            // hookEl.scrollIntoView();

             //采用scrollTo配合设置的锚点来自动滚动到指定区域
            switch (name) {
                case `${this.platClass}-news`:
                    scrollEl.scrollTo(vm.scrollAx, 0);
                    vm.menuIndex = `${this.platClass}-news`;
                    break;

                case `${this.platClass}-manaual`:
                    scrollEl.scrollTo(vm.scrollBx, scrollAy * 0.8 + 16);
                    console.log("-------scrollAy + 16", scrollAy);
                    vm.menuIndex = `${this.platClass}-manaual`;
                    vm.scrollAy = scrollAy;
                    break;

                case `${this.platClass}-learn`:
                    scrollEl.scrollTo(vm.scrollCx, scrollAy + scrollBy + 32);
                    vm.menuIndex = `${this.platClass}-learn`;
                    break;

                case `${this.platClass}-video`:
                    scrollEl.scrollTo(
                        vm.scrollDx,
                        scrollAy + scrollBy + scrollCy + 48
                    );
                    vm.menuIndex = `${this.platClass}-video`;
                    break;

                default:
                    break;
            }
        },
        //scroll-view的滚动事件
        scroll(e) {
            let vm = this;

            console.log("-----------eeeeeeee", e.detail.scrollTop);
            //获取滚动长度
            let scrollTop = e.detail.scrollTop;

            //获取各个组件的高度
            let scrollAy = document.querySelector(
                `#${vm.platClass}-news`
            ).offsetHeight;
            let scrollBy = document.querySelector(
                `#${vm.platClass}-manaual`
            ).offsetHeight;
            let scrollCy = document.querySelector(
                `#${vm.platClass}-learn`
            ).offsetHeight;
            let scrollDy = document.querySelector(
                `#${vm.platClass}-video`
            ).offsetHeight;

            console.log(
                "------scroll-view的滚动事件-222222222222---------",
                scrollAy,
                scrollBy,
                scrollCy,
                scrollDy
            );

            if (scrollTop < scrollAy / 2) {
                this.menuIndex = `${this.platClass}-news`;
            }
            if (scrollTop > scrollAy * 0.8) {
                this.menuIndex = `${this.platClass}-manaual`;
            }
            if (scrollTop > scrollAy * 0.8 + scrollBy / 2) {
                this.menuIndex = `${this.platClass}-learn`;
            }
            if (scrollTop > scrollAy + scrollBy + scrollCy / 4) {
                this.menuIndex = `${this.platClass}-video`;
            }
        },
    },
};
</script>

<style scoped lang="less">
.module-tabs {
    display: flex;
    padding: 8rpx 24rpx 30rpx;
    background: #fff;

    position: fixed;
    z-index: 99;
    top: 0;
    width: 100%;
    .tabs-button {
        width: 160rpx;
        height: 68rpx;
        background: #f3f4f7;

        border-radius: 8rpx;
        font-size: 28rpx;
        text-align: center;
        line-height: 68rpx;
        margin-right: 20rpx;
    }

    .tabs-button.active {
        border: 1px solid #0a63f1;

        color: #0a63f1;
    }
}
</style>
 类似资料: