React实现菜单栏滚动功能

 更新时间:2024年03月25日 11:02:47   作者:卡卡舅舅  
本文将会基于react实现滚动菜单栏功能,点击菜单,内容区域会自动滚动到对应卡片,内容区域滑动,指定菜单栏会被选中,代码简单易懂,感兴趣的朋友一起看看吧

简介

        本文将会基于react实现滚动菜单栏功能。

技术实现

实现效果

       点击菜单,内容区域会自动滚动到对应卡片。内容区域滑动,指定菜单栏会被选中。

ScrollMenu.js

import {useRef, useState} from "react";
import './ScrollMenu.css';
export const ScrollMenu = ({products}) => {
    // 获取 categoryProductMap
    const categoryProductMap = new Map();
    products.forEach(product => {
        const category = product.category;
        let categoryProductList = categoryProductMap.get(category);
        if (!categoryProductList) {
            categoryProductList = [];
        }
        categoryProductList.push(product);
        categoryProductMap.set(category, categoryProductList);
    });
    // 获取类别列表
    const categoryList = Array.from(categoryProductMap.keys());
    // 菜单选中索引
    const [current, setCurrent] = useState(0);
    /**
     * 内容引用
     */
    const contentRef = useRef();
    /**
     * 当左侧菜单点击时候
     */
    const onMenuClick = (idx) => {
        if (idx !== current) {
            // 内容自动滚动到对应菜单位置
            contentRef.current.scrollTop = height.slice(0, idx).reduce((a, b) => a + b, 0);
            setCurrent(idx);
        }
    }
    /**
     *  计算右侧商品类别卡片高度
     */
    const height = [];
    const itemHeight = 25;
    categoryList.forEach((category, index) => {
        var productCnt = categoryProductMap.get(category).length;
        height.push((productCnt + 1) * itemHeight); // 0.8 是header高度
    });
    console.log(height)
    /**
     * 当右侧内容滚动时候
     */
    const onContentScroll = () => {
        const scrollTop = contentRef.current.scrollTop;
        if (current < height.length - 1){
            const nextIdx = current + 1;
            // 计算下一个位置高度
            const nextHeight = height.slice(0, nextIdx).reduce((a, b) => a + b, 0);
            console.log('scrollTop', scrollTop, 'nextHeight', nextHeight, 'nextIdx', nextIdx)
            if (scrollTop >= nextHeight) {
                contentRef.current.scrollTop = nextHeight;
                setCurrent(nextIdx);
                return;
            }
        }
        if (current > 0) {
            const lastIdx = current - 1;
            // 计算上一个位置高度
            const lastHeight = height.slice(0, lastIdx).reduce((a, b) => a + b, 0);
            console.log('scrollTop', scrollTop, 'lastHeight', lastHeight, 'lastIdx', lastIdx)
            if (scrollTop <= lastHeight) {
                contentRef.current.scrollTop = lastHeight;
                setCurrent(lastIdx);
                return;
            }
        }
    }
    return (
        <div className='scroll-menu'>
            <div className='menu'>
                {
                    // 菜单列表
                    categoryList.map((category, index) => {
                        return (
                            <div className={"menu-item" + ((index === current )? '-active' : '')}
                                 key={`${index}`} id={`menu-item-${index}`}
                                 onClick={(event) => {
                                     onMenuClick(index)
                                 }}>
                                {category}
                            </div>
                        )
                    })
                }
            </div>
            <div className='content' ref={contentRef} onScroll={(event) => {
                onContentScroll()
            }}>
                {
                    categoryList.map((category, index) => {
                        // 获取类别商品
                        const productList = categoryProductMap.get(category);
                        return (
                            <div key={index}>
                                <div className='content-item-header' key={`${index}`}
                                     id={`content-item-${index}`} style={{
                                    height: itemHeight
                                }} >{category}</div>
                                {
                                    productList.map((product,idx) => {
                                        return <div className='content-item-product'style={{
                                            height: itemHeight
                                        }}  key={`${index}-${idx}`} >{product.name}</div>
                                    })
                                }
                            </div>
                        )
                    })
                }
            </div>
        </div>
    )
}

ScrollMenu.css

.scroll-menu {
    display: flex;
    flex-direction: row;
    width: 300px;
    height: 100px;
}
.menu{
    width: 90px;
    height: 100px;
    display: flex;
    flex-direction: column;
}
.menu-item {
    text-align: center;
    vertical-align: middle;
}
.menu-item-active {
    text-align: center;
    vertical-align: middle;
    background-color: lightcoral;
}
.content {
    width: 210px;
    overflow: auto;
}
.content-item-header{
    text-align: left;
    vertical-align: top;
    background-color: lightblue;
}
.content-item-product{
    text-align: center;
    vertical-align: center;
    background-color: lightyellow;
}

App.js

import './App.css';
import {ScrollMenu} from "./component/scroll-menu/ScrollMenu";
const App = ()=> {
    const products = [
        {
            category:'蔬菜',
            name:'辣椒'
        },
        {
            category:'蔬菜',
            name:'毛豆'
        },
        {
            category:'蔬菜',
            name:'芹菜'
        },
        {
            category:'蔬菜',
            name:'青菜'
        },
        {
            category:'水果',
            name:'苹果'
        },
        {
            category:'水果',
            name:'梨'
        },
        {
            category:'水果',
            name:'橘子'
        },   {
            category:'食物',
            name:'肉'
        },   {
            category:'食物',
            name:'罐頭'
        }
        ,   {
            category:'食物',
            name:'雞腿'
        }
    ];
    return (
        <ScrollMenu products={products}/>
    )
}
export default App;

到此这篇关于React实现菜单栏滚动的文章就介绍到这了,更多相关React 菜单栏滚动内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • react动态路由的实现示例

    react动态路由的实现示例

    React中动态路由通过ReactRouter库实现,根据应用状态或用户交互动态显示或隐藏组件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • React配置多个代理实现数据请求返回问题

    React配置多个代理实现数据请求返回问题

    这篇文章主要介绍了React之配置多个代理实现数据请求返回问题,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • 深入掌握 react的 setState的工作机制

    深入掌握 react的 setState的工作机制

    本篇文章主要介绍了深入掌握 react的 setState的工作机制,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • 手动用webpack搭建第一个ReactApp的示例

    手动用webpack搭建第一个ReactApp的示例

    本篇文章主要介绍了手动用webpack搭第一个 ReactApp的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • react中使用video.js的踩坑记录

    react中使用video.js的踩坑记录

    这篇文章主要介绍了react中使用video.js的踩坑记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • react实现复选框全选和反选组件效果

    react实现复选框全选和反选组件效果

    这篇文章主要为大家详细介绍了react实现复选框全选和反选组件效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • react中的双向绑定你真的了解吗

    react中的双向绑定你真的了解吗

    这篇文章主要为大家详细介绍了react中的双向绑定,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • 如何使用Redux Toolkit简化Redux

    如何使用Redux Toolkit简化Redux

    redux-toolkit是目前redux官方推荐的编写redux逻辑的方法,针对redux的创建store繁琐、样板代码太多、依赖外部库等问题进行了优化,官方总结了四个特点是简易的/有想法的/强劲的/高效的,总结来看,就是更加的方便简单了
    2022-12-12
  • react 项目 中使用 Dllplugin 打包优化技巧

    react 项目 中使用 Dllplugin 打包优化技巧

    在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,vue 我们希望能和自己的代码分离开,这篇文章主要介绍了react 项目 中 使用 Dllplugin 打包优化,需要的朋友可以参考下
    2023-01-01
  • react源码层深入刨析babel解析jsx实现

    react源码层深入刨析babel解析jsx实现

    同作为MVVM框架,React相比于Vue来讲,上手更需要JavaScript功底深厚一些,本系列将阅读React相关源码,从jsx -> VDom -> RDOM等一些列的过程,将会在本系列中一一讲解
    2022-10-10

最新评论