前端仿美团菜单双侧菜单联动

工作中遇到一个左右菜单联动的需求,记录一下。

如图


微信图片_20220718155405.png

主要的实现功能
1.点击左侧右侧滚动到对应位置
2.右侧滑动,左侧对应图标选中

  1. 滚动到相应位置
document.getElementById('item' + item.appTypeName).scrollIntoView({
        block: 'start',
        behavior: 'smooth'
})

2.我的思路是检测所有可见范围的item是否可见,其中index最小的就是左侧应该显示index.
检查可见item
getBoundingClientRect 是元素距离可见试图做左上角的距离

checkVisible(elm) {
        var rect = elm.getBoundingClientRect();
        //获取当前浏览器的视口高度,不包括工具栏和滚动条
        //document.documentElement.clientHeight兼容 Internet Explorer 8、7、6、5
        var viewHeight=Math.max(document.documentElement.clientHeight,window.innerHeight);
        //bottom top是相对于视口的左上角位置
        //bottom大于0或者top-视口高度小于0可见
        return !(rect.bottom < 70 || rect.top - viewHeight >= 0);
},

这边会有一个问题scroll事件会频繁触发,导致右侧菜单在滚动时左侧每一个都会亮一次,比如右侧从2滑动到5,2345都会一次亮一次,所以我做了一下防抖,

onScroll(e) {
    if (timer) {
        clearTimeout(timer);
    }
    timer = setTimeout(() => {
        this.scorlling = false
        this.$nextTick(() => {
        let count = []
        this.tabDataList.forEach((item, index) => {
        //查找可见item
            if (this.checkVisible(document.getElementById('item' + item.appTypeName))) {
                count.push(index)
                }
            })
            //找出最小的
            let index = Math.min(...count)
            if (this.selecting) {
                return
            } else {
                this.selectName = this.tabDataList[index].appTypeName
            }
        })
    }, 100)
},

下面是布局文件
因为是移动端的,使用了uniapp和vant,可以根据自己的项目更改

<view class="fun-body" @touchmove.stop @touch.stop>
            <view class="left-content">
                <view v-for="(item,index) in tabDataList"
                    :class="selectName==item.appTypeName?['left-item','left-item-select']:['left-item']"
                    @click="selectIndex(item)" :href="'#item.appTypeName'">
                    <view :class="selectName==item.appTypeName?['slect-blue']:['slect-gray']"></view><span
                        style="margin-left: 18rpx;"
                        :class="selectName==item.appTypeName?['slect-blue-text']:['slect-gray-text']">{{item.appTypeName}}</span>
                </view>
            </view>
            <view class="right-content" @touchmove.stop @touch.stop @scroll.passive="onScroll">
                <view v-for="item in tabDataList" class="right-item" :id="'item' + item.appTypeName">
                    <view class="item-title">
                        {{item.appTypeName}}
                    </view>
                    <u-grid :border="false">
                        <u-grid-item v-for="childrenItem in item.appSysMenuVoList" class="gr-item"
                            @click="toDetail(childrenItem)">
                            <view :class="['icon', childrenItem.appIcon ,'icon-width']"></view>
                            <view class="bottom-center-text">
                                {{childrenItem.appMenuName}}
                            </view>
                        </u-grid-item>
                    </u-grid>
                    <view style="background-color:#EBEDF0 ;margin-bottom: 16rpx;height: 15rpx;"></view>
                </view>
                <view style="height: 1330rpx;"></view>
            </view>
        </view>

2023/07/06
最近写视屏懒加载发现另一种判断是否在可视区域的方法记录一下
IntersectionObserver是一个可以判断是否在可视区域的方法,不过也需要做好节流

const intersectionObserver = new IntersectionObserver((entries) => {
  // 如果 intersectionRatio 为 0,则目标在视野外,
  entries.forEach((entry) => {
    if (entry.intersectionRatio > 0) {
      // console.log("在视野范围", entry.target.id);
    } else {
      // console.log("不在视野范围", entry.target.id);
    }
  });
});

onMounted(() => {
    // 开始监听
    intersectionObserver.observe(
      document.getElementById(`${props.data.id}`) as any
    );
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容