实现简单的tab切换--滚动切换,点击切换

tab切换时是项目中经常用到的,把这个功能记录下来,共享

<!--
  思路:
  1,右侧3个tab导航名称。注意:2种样式,未选中的样式,选中的那个改变样式
  2. 左侧对应tab的内容。 注意:数据格式,循环出来的
  [
    title: '导航',
    subtitle: '线性图标',
    icons: [
        {
            url: '../../a.svg',
            name: '张'
        },
        {
            url: '../../a.svg',
            name: '张'
        }
    ],
    title: '装饰',
    subtitle: '线性图标',
    icons: [
        {
            url: '../../b.svg',
            name: '张'
        },
    ]
  ]
  3. 加滚动事件 注意:可以选择原生,可以引用插件vue-scrollto;通过ref获取标题节点和滚动的区域大小
  4. 加点击监听事件,获取id,把id这个div上加scrollIntoView这个事件

  知识点:
  滚动事件
    cnblogs.com/97z4moon/p/14566564.html
    window.addEventListener('scroll',this.handleScroll,true)
    // 添加滚动监听 -- 第一个参数是事件类型,第二个事件是函数,第三个参数true防止监听事件无效
    document.documentElement.scrollTop;   // 获取滚动条位置;要获取当前页面的滚动条纵坐标位置;documentElement对应的是html
    document.body.scrollTop;  // 对应的是body标签,上面的更准确
    window.pageYOffset;       // 返回文档在窗口左上角垂直方向的滚动像素
  点击事件
    document.getElementById: 获取id
    Element.scrollIntoView方法让当前的元素滚动到浏览器窗口的可视区域内
    默认为true: 滚动到顶部
    false:滚动到底部
    behavior: 属性定义动画过度效果
    block:垂直方向的对齐
    inline:水平方向的对齐
    element.getBoundingClientRect():https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect
滚动页面:
有时也可以用offsettop和scrolltop
-->

代码如下:

<template>
    <div>
        <div class="wrapper">
            <!-- 左侧内容 -->
            <div class="wrapper-left">
                <!-- id dom节点,是为了样式 -->
                <div
                    class="icons"
                    v-for="(item,index) in iconList"
                    :id="`tab-${index+1}`"
                    :key="index">
                    <div class="icons-title" :ref="`tab${index + 1}`">{{item.title}}</div>
                    <div class="icons-subtitle">{{item.subtitle}}</div>
                    <div class="icons-icon">
                        <div
                            class="block"
                            v-for="(itemChild,index) in item.icons"
                            :key="index">
                            <img :src="itemChild.url" id="girlImg" >
                            <div class="name">{{ itemChild.name }}</div>
                        </div>
                    </div>
                </div>
            </div>
            <!-- 右侧tab -->
            <div class="wrapper-right">
                <div class="tab">
                    <ul>
                        <li id="nav1" :class="{'select-tab': active === 1}" @click="setTab(1)">导航图标</li>
                        <li id="nav2" :class="{'select-tab': active === 2}" @click="setTab(2)">操作图标</li>
                        <li id="nav3" :class="{'select-tab': active === 3}" @click="setTab(3)">装饰图标</li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: "Tab",
    data(){
        return {
            active: 1,// 选中tab
            cancelScroll: false,
            iconList: [
                {
                    title: '导航图标',
                    subtitle: '线性图标',
                    icons: [
                        {
                            url: require('../../../src/assets/icon/icon_1.1.1.2首页02.svg'),
                            name: '首页'
                        },
                        {
                            url: require('../../../src/assets/icon/icon_1.1.1.3资料.svg'),
                            name: '资料'
                        }
                    ],
                },
                {
                    title: '操作图标',
                    subtitle: '线性图标',
                    icons: [
                        {
                            url: require('../../../src/assets/icon/icon_2.1.1.1编辑.svg'),
                            name: '编辑'
                        }
                    ]
                },
                {
                    title: '装饰图标',
                    subtitle: '线性图标',
                    icons: [
                        {
                            url: require('../../../src/assets/icon/icon_3.1.1.1word.svg'),
                            name: 'word'
                        }
                    ],
                }
            ]
        };
    },
    mounted() {
        window.addEventListener('scroll', this.handleScroll,true);
    },

    beforeDestroy () {
        // 清除监听
        // Cannot read property ‘getBoundingClientRect‘ of undefined
        window.removeEventListener('scroll', this.handleScroll,true);
    },
    methods:{

        /**
         * 选中点击事件
         * @param tab
         */
        setTab(tab){
            this.active = tab;
            document.getElementById(`tab-${tab}`).scrollIntoView({ behavior : "smooth", block: "start" });

            // 解决点击tab的时候跳到上一个tab(晃一下)问题; 也就是触发点击事件的同时也出发了滚动事件
            this.cancelScroll = true;
            setTimeout(() =>{
                this.cancelScroll = null;
            });
        },

        /**
         * 滚动监听事件
         */
        handleScroll(){

            if (this.cancelScroll){
                return;
            }

            // this.$refs 获取的是节点 不是数组
            let tab1top = this.$refs['tab1'][0].getBoundingClientRect().top;
            let tab2top = this.$refs['tab2'][0].getBoundingClientRect().top;
            let tab3top = this.$refs['tab3'][0].getBoundingClientRect().top;

            console.log(document.documentElement.scrollTop, '页面滚出');

            // 86是怎么算的?也可以是0,小于0就是滚出去;(内容超出自己的高度,才会有滚动)
            // 第一个tab的滚动的距离
            if (tab1top < 0 && tab2top > 0){
                this.active = 1;
            }

            // 第二个tab的滚动的距离
            if (tab2top < 0 && tab3top > 0){
                this.active = 2;
            }

            // 第三个tab的滚动的距离
            if (tab3top < 0){
                this.active = 3;
            }
        }
    }
};
</script>

<style scoped lang="scss">
.wrapper{
    width: 100%;
    height: 100%;
    margin: 20px 50px;
    display: flex;
    flex-direction: row;
    &-left{
        flex: 1;
        .icons{
            &-title{
                font-size: 20px;
                color: #09102B;
                letter-spacing: 0;
                margin: 44px 0 36px;
                display: flex;
                align-items: center;
            }
            &-subtitle{
                font-size: 13px;
                color: #667186;
                letter-spacing: 0;
                line-height: 22px;
                margin-top: 10px;
            }
            &-icon{
                display: flex;
                flex-direction: row;
                flex-wrap: wrap;
                margin-top: 30px;
                .block{
                    border: 1px solid #F0F0F0;
                    width: 117px;
                    height: 128px;
                    margin-right: 36px;
                    border-radius: 12px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    flex-direction: column;
                    margin-bottom: 24px;
                    .name{
                        padding-top: 20px;
                    }
                }
            }
        }
    }
    &-right{
        width: 300px;
        .tab{
            position: fixed;
            ul{
                list-style: none;
                // 未选中情况下的样色
                li{
                    padding:0;
                    background: #EEF1F6;
                    border-radius: 3px 100px 100px 98px;
                    cursor:pointer;
                    text-align:center;
                    text-decoration:none;
                    width:100px;
                    font-size:12px;
                    height:30px;
                    line-height:30px;
                    margin:10px 0px 10px 0;
                    position:relative;
                    color: #ADB1C3;
                }
                // 选中的样式
                .select-tab{
                    background: #0F59BA;
                    border-bottom-color:#fff;
                    cursor:default;
                    font-weight:bold;
                    font-size: 12px;
                    height:30px;
                    line-height:30px;
                    color: #FFFFFF;
                    text-align: center;
                }
            }
        }
    }
}
</style>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值