uniapp菜单左右关联

<template>
    <view class="content">
        <view class="u-wrap">
            <view class="u-menu-wrap">
                <scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop"
                    :scroll-into-view="itemId">
                    <view v-for="(item,index) in content" :key="index" class="u-tab-item"
                        :class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)">
                        <text class="u-line-1">{{item.title}}</text>
                    </view>
                </scroll-view>
                <scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box"
                    @scroll="rightScroll">
                    <view class="page-view">
                        <view class="class-item" :id="'item' + index" v-for="(item , index) in content" :key="index">
                            <view class="item-title">
                                <text>{{item.title}}</text>
                            </view>
                            <view class="item-container">
                                <view class="thumb-box" v-for="(item1, index1) in item.options" :key="index1"
                                    @click="featureC(item1.cat, item1.name)">
                                    <image v-if="item1.icon != ''" class="item-menu-image" :src="item1.src" mode="">
                                    </image>
                                    <view v-else class="item-menu-image row-c" style="background-color: #F4F6F8;"><text
                                            style="font-size: 20rpx;color: #d0d0d0;">加载失败</text></view>
                                    <view class="item-menu-name">{{item1.text}}</view>
                                </view>
                            </view>
                        </view>
                    </view>
                </scroll-view>
            </view>
        </view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                scrollTop: 0, //tab标题的滚动条位置
                oldScrollTop: 0, // tab标题的滚动条旧位置
                current: 0, // 预设当前项的值
                menuHeight: 0, // 左边菜单的高度
                menuItemHeight: 0, // 左边菜单item的高度
                itemId: '', // 栏目右边scroll-view用于滚动的id
                // tabbar: JSON.parse(uni.getStorageSync('categroy')), // 渲染的数据,放在最后供你们测试
                arr: [], // 储存距离顶部高度的数组
                scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
                timer: null, // 定时器
                category: [{
                        name: '新品',
                        id: 'a1'
                    },
                    {
                        name: '众筹',
                        id: 'a2'
                    },
                    {
                        name: '小米手机',
                        id: 'a3'
                    },
                    {
                        name: 'redmi手机',
                        id: 'a4'
                    },
                    {
                        name: '黑鲨游戏',
                        id: 'a5'
                    },
                    {
                        name: "手机配件",
                        id: 'a6'
                    },
                    {
                        name: '电视',
                        id: 'a7'
                    },
                    {
                        name: '电脑',
                        id: 'a8'
                    },
                ],
                content: [{
                        title: '- 新品 -',
                        options: [{
                                src: '../../static/logo.png',
                                id: '001',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '002',
                                text: 'redmi8A'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '003',
                                text: '小米9pro 5G'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '004',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '005',
                                text: 'redmi8'
                            }
                        ],
                        id: 'a1'
                    },
                    {
                        title: '- 众筹 -',
                        options: [{
                                src: '../../static/logo.png',
                                id: '006',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '007',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '008',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '009',
                                text: '美味寒冰啊'
                            }
                        ],
                        id: 'a2'
                    },
                    {
                        title: '- 小米手机 -',
                        options: [{
                                src: '../../static/logo.png',
                                id: '006',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '007',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '008',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '009',
                                text: 'redmi8'
                            }
                        ],
                        id: 'a3'
                    },
                    {
                        title: '- redmi手机 -',
                        options: [{
                                src: '../../static/logo.png',
                                id: '006',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '007',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '008',
                                text: 'redmi8'
                            },
                            {
                                src: '../../static/logo.png',
                                id: '009',
                                text: 'redmi8'
                            }
                        ],
                        id: 'a4'
                    }
                ],
            }
        },
        onLoad() {
            this.getMenuItemTop()
        },
        methods: {
              getElRect(elClass, dataVal) {
                    new Promise((resolve, reject) => {
                        const query = uni.createSelectorQuery().in(this);
                        query.select('.' + elClass).fields({
                            size: true
                        }, res => {
                            // 如果节点尚未生成,res值为null,循环调用执行
                            if (!res) {
                                setTimeout(() => {
                                    this.getElRect(elClass);
                                }, 10);
                                return;
                            }
                            this[dataVal] = res.height;
                            resolve();
                        }).exec();
                    })
                },
            getMenuItemTop() {
                new Promise(resolve => {
                    let selectorQuery = uni.createSelectorQuery();
                    selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
                        // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
                        if (!rects.length) {
                            setTimeout(() => {
                                this.getMenuItemTop();
                            }, 10);
                            return;
                        }
                        rects.forEach((rect) => {
                            // 视情况而定,这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
                            // this.arr.push(rect.top - rects[0].top);
                            this.arr.push(rect.top)
                            resolve();
                        })
                    }).exec()
                })
            },
            async observer() {
                this.content.map((val, index) => {
                    let observer = uni.createIntersectionObserver(this);
                    observer.relativeTo('.right-box', {
                        top: 0
                    }).observe('#item' + index, res => {
                        if (res.intersectionRatio > 0) {
                            let id = res.id.substring(4);
                            this.leftMenuStatus(id);
                        }
                    })
                })
            },
            /**
             * 设置左边菜单的滚动状态
             * @index 传入的 ID
             */
            async leftMenuStatus(index) {
                this.current = index;
                // 如果为0,意味着尚未初始化
                if (this.menuHeight == 0 || this.menuItemHeight == 0) {
                    await this.getElRect('menu-scroll-view', 'menuHeight');
                    await this.getElRect('u-tab-item', 'menuItemHeight');
                }
                // 将菜单活动item垂直居中
                this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
            },
            async swichMenu(index) {
                if (this.arr.length == 0) {
                    await this.getMenuItemTop();
                }
                if (index == this.current) return;
                this.scrollRightTop = this.oldScrollTop;
                this.$nextTick(function() {
                    this.scrollRightTop = this.arr[index];
                    this.current = index;
                    this.leftMenuStatus(index);
                })
            },
            async rightScroll(e) {
                this.oldScrollTop = e.detail.scrollTop;
                if (this.arr.length == 0) {
                    await this.getMenuItemTop();
                }
                if (this.timer) return;
                if (!this.menuHeight) {
                    await this.getElRect('menu-scroll-view', 'menuHeight');
                }
                setTimeout(() => { // 节流
                    this.timer = null;
                    // scrollHeight为右边菜单垂直中点位置
                    // let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
                    // scrollHeight为右边菜单头部位置
                    let scrollHeight = e.detail.scrollTop + 20;
                    for (let i = 0; i < this.arr.length; i++) {
                        let height1 = this.arr[i];
                        let height2 = this.arr[i + 1];
                        if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
                            this.leftMenuStatus(i);
                            return;
                        }
                    }
                }, 10)
            }
        }
    }
</script>

<style>
    .u-wrap {
        /* #ifdef H5 */
        height: calc(100vh - var(--window-top));
        /* #endif */
        display: flex;
        flex-direction: column;
        height: 100vh;
    }

    .u-search-box {
        padding: 18rpx 30rpx;
    }

    .u-menu-wrap {
        flex: 1;
        display: flex;
        overflow: hidden;
    }

    .u-tab-view {
        width: 200rpx;
        height: 100%;
    }

    .u-tab-item {
        height: 110rpx;
        background: #f6f6f6;
        box-sizing: border-box;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 26rpx;
        color: #444;
        font-weight: 400;
        line-height: 1;
    }

    .u-tab-item-active {
        position: relative;
        color: #06A446;
        font-size: 30rpx;
        font-weight: 500;
        background: #D6FFE7;
    }

    .u-tab-item-active::after {
        content: "";
        position: absolute;
        border-left: 4px solid #06A446;
        height: 52rpx;
        left: 0;
        top: 29rpx;
    }

    .u-tab-view {
        height: 100%;
    }

    .right-box {
        background-color: rgb(250, 250, 250);
    }

    .page-view {
        padding: 16rpx;
    }

    .class-item {
        margin-bottom: 30rpx;
        background-color: #fff;
        padding: 16rpx;
        border-radius: 8rpx;
    }

    .class-item:last-child {
        min-height: 100vh;
    }

    .item-title {
        font-size: 26rpx;
        color: $u-main-color;
        font-weight: bold;
    }

    .item-menu-name {
        margin-top: 8rpx;
        font-weight: normal;
        font-size: 24rpx;
        color: $u-main-color;
    }

    .item-container {
        display: flex;
        flex-wrap: wrap;
    }

    .thumb-box {
        width: 33.333333%;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
        margin-top: 20rpx;
    }

    .item-menu-image {
        width: 120rpx;
        height: 120rpx;
    }
</style>
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
uniapp 是一个基于 Vue.js 的跨平台开发架,它可以帮助开发者快速构建出多端(如:iOS、Android、H5、小程序等)的应用程序。在 uniapp 中,可以使用内置的组件和 API 来实现菜单栏的功能。 菜单栏是一个常用的 UI 组件,通常用于导航和切换页面。在 uniapp 中,菜单栏可以通过内置的 tabbar 组件来实现。tabbar 组件可以在底部或顶部显示一组菜单项,每个菜单项通常对应着一个页面或一组相关页面。 使用 tabbar 组件时,需要在页面配置文件(如:pages.json)中设置 "tabBar" 字段,并定义菜单项的样式和跳转路径。同时,在每个要显示的页面中也需要设置对应的菜单项的索引值(即 tabBar 中定义的 list 数组中的索引值)。 以下是一个简单的例子: ``` // pages.json { "tabBar": { "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "static/tabbar/home.png", "selectedIconPath": "static/tabbar/home-selected.png" }, { "pagePath": "pages/cart/cart", "text": "购物车", "iconPath": "static/tabbar/cart.png", "selectedIconPath": "static/tabbar/cart-selected.png" }, { "pagePath": "pages/user/user", "text": "个人中心", "iconPath": "static/tabbar/user.png", "selectedIconPath": "static/tabbar/user-selected.png" } ] } } // index.vue <template> <view> <text>这是首页</text> </view> </template> <script> export default { onTabItemTap(item) { console.log(item.index) // 输出当前菜单项的索引值 } } </script> ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值