目标问题

进入页面后,滚动一定距离使其吸顶。滚动到某DOM可视区域后,Tab拦当前选项主动滑动到该DOM上。且点击tab拦会定位到对应的dom位置。
效果图
实现效果动图

在这里插入图片描述

实现目的——html结构
<template>
    <div class="tab__main" :style="prop.box_style ? prop.box_style : ''">
        <div class="tab__div">
            <ul class="tab__list" :style="prop.attr.tab_style ? prop.attr.tab_style : ''">
                <li class="tab__item"  v-for="(tabs, index) in prop.attr.tab_content" :key="tabs.tab_menu" @click="onClickTabs(index)"
                >
                    <span :style="tabStyle(index)">{{ tabs.tab_menu }}</span>
                </li>
            </ul>
            <div class="active__line" :style="prop.attr.cur_slide_style ? prop.attr.cur_slide_style : ''"></div>
        </div>
    </div>
</template>
实现目的——less样式
.tab__div {
    width: 100%;
    height: 102px;
    position: relative;
    padding-top: 36px;
    background-color: #fff;
    .tab__list {
        display: flex;
        .tab__item {
            flex: 1;
            font-size: 32px;
        }
        .tab__item-current {
            font-weight: 700;
        }
    }
    .active__line {
        position: absolute;
        bottom: 0;
        left: 0;
        width: 187.5px;
        height: 5px;
        background-color: #4B8FFB;
        transition: all 300ms;
    }
}
实现目的——js部分
export default {
    name: 'TabModule',
    props: {
        prop: {
            type: Object
        }
    },
    data () {
        return  {
            scrolltop: null,
            dom: null,
            domobj: {}  // 各个dom的页面位置
        }
    },
    computed: {
        tabStyle () {
            return function (params) {
                return this.prop.attr.tab_content[params].tab_style || ''
            }
        }
    },
    mounted () {
        this.onWatchScroll()
        // 这里首次进入页面当前选中项为第一个
        document.querySelectorAll('.tab__item')[0].style = this.prop.attr.cur_tab_style ? this.prop.attr.cur_tab_style : ''
    },
    methods: {
        // 获取各个dom的页面位置
        getDomsObj () {
            this.domobj.dom1 = document.querySelectorAll(`#${this.prop.attr.tab_content[0].anchor_point}`)[0].offsetTop
            this.domobj.dom2 = document.querySelectorAll(`#${this.prop.attr.tab_content[1].anchor_point}`)[0].offsetTop
            this.domobj.dom3 = document.querySelectorAll(`#${this.prop.attr.tab_content[2].anchor_point}`)[0].offsetTop
            this.domobj.dom4 = document.querySelectorAll(`#${this.prop.attr.tab_content[3].anchor_point}`)[0].offsetTop
        },
        // 计算当前选中滑动块儿的滑动距离和当前选中项
        computerSlide (val) {
            let tablist = document.querySelectorAll('.tab__item')
            for (let i = 0; i < tablist.length; i++) {
                tablist[i].style = ''
            }
            document.querySelector('.active__line').style.transform = `translateX(${(val * document.querySelector('.active__line').offsetWidth)}px)`
            // 当前选中的tab_item的状态
            tablist[val].style = this.prop.attr.cur_tab_style ? this.prop.attr.cur_tab_style : ''
        },
        onClickTabs (index) {
            this.computerSlide(index)
            // 计算点击后滑动到DOM的位置
            this.dom = document.querySelectorAll(`#${this.prop.attr.tab_content[index].anchor_point}`)[0].offsetTop
            let tabbox = document.querySelectorAll('.tab__div')[0]
            if (index === 0) {
                if (tabbox.style.position === 'relative') {
                    window.scrollTo(0, this.dom - tabbox.clientHeight)
                    return
                }
                window.scrollTo(0, this.dom)
                return
            }
            if (index === 3) {
                window.scrollTo(0, this.dom)
                return
            }
            if (tabbox.style.position === 'relative') {
                window.scrollTo(0, this.dom - (tabbox.clientHeight * 2))
            } else {
                window.scrollTo(0, this.dom - tabbox.clientHeight)
            }
        },
        onWatchScroll () {
            let tabmain = document.querySelectorAll('.tab__main')[0]
            let tabdiv = document.querySelectorAll('.tab__div')[0]
            tabdiv.style.top = 0
            window.onscroll = () => {
                // 由于在created()或者mounted()钩子函数中获取到的dom位置不对,在滑动中获取dom的页面位置
                this.getDomsObj()
                this.scrolltop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset
                // 滑动根据滚动距离来计算当前可是区域的选中项
                this.onScrollPage()
                // 自定义吸顶效果
                if (this.scrolltop > tabmain.offsetTop) {
                    tabdiv.style.position = 'fixed'
                    tabdiv.style['z-index'] = 99
                } else {
                    tabdiv.style.position = 'relative'
                    tabdiv.style['z-index'] = 0
                }
            }
        },
        onScrollPage () {
            let tab = document.querySelectorAll('.tab__div')[0]
            if (this.scrolltop > this.domobj.dom1 && this.scrolltop < (this.domobj.dom2 - tab.offsetHeight * 2)) {
                this.computerSlide(0)
            } else if (this.scrolltop > (this.domobj.dom2 - tab.offsetHeight * 2) && this.scrolltop < this.domobj.dom3 - tab.offsetHeight * 2) {
                this.computerSlide(1)
            } else if (this.scrolltop > (this.domobj.dom3 - tab.offsetHeight * 2) && this.scrolltop < (this.domobj.dom3 + tab.offsetHeight * 2)) {
                this.computerSlide(2)
            } else if (this.scrolltop > (this.domobj.dom4 - tab.offsetHeight * 10) && this.scrolltop < this.domobj.dom4) {
                this.computerSlide(3)
            }
        }
    }
}
完成目的——页面引用组件
<template>
    <div>
        <div class="div__header"></div>
        <tab-module :prop="tabattributes"></tab-module>
        <div :id="tabattributes.attr.tab_content[index].anchor_point" class="div__item" v-for="(item, index) in fordiv" :key="item">{{ item }}</div>
        <div class="div__footer">我是有底线的</div>
    </div>
</template>

import TabModule from '../../components/TabModule.vue'
export default {
    components: {
        TabModule
    },
    data () {
        return {
            tabattributes: {
                box_style: "margin-top: 10px;",                 
                attr: {           
                    cur_tab_style: "font-weight: 700;", 
                    cur_slide_style: "",
                    tab_content: [{
                        tab_menu: "控件1",             
                        anchor_point: "DomPoint1",
                        tab_style: "" 
                    }, {
                        tab_menu: "控件2",             
                        anchor_point: "DomPoint2",   
                        tab_style: "" 
                    }, {
                        tab_menu: "控件3",             
                        anchor_point: "DomPoint3",   
                        tab_style: "" 
                    }, {
                        tab_menu: "控件4",             
                        anchor_point: "DomPoint4", 
                        tab_style: "" 
                    }]
                }
            },
            fordiv: ['页面控件1', '页面控件2', '页面控件3', '页面控件4']
        }
    }
}

<style lang="less" scoped>
.div__header {
    width: 100%;
    height: 200px;
    background-color: #909;
}
.div__item {
    width: 100%;
    height: 400px;
    background-color: rgb(78, 215, 224);
    text-align: center;
    font-size: 26px;
}
.div__footer {
    width: 100%;
    height: 200px;
    background-color: #090;
}
</style>
Logo

前往低代码交流专区

更多推荐