当前位置:   article > 正文

React - 实现菜单栏滚动

React - 实现菜单栏滚动

简介

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

技术实现

实现效果

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

ScrollMenu.js
  1. import {useRef, useState} from "react";
  2. import './ScrollMenu.css';
  3. export const ScrollMenu = ({products}) => {
  4. // 获取 categoryProductMap
  5. const categoryProductMap = new Map();
  6. products.forEach(product => {
  7. const category = product.category;
  8. let categoryProductList = categoryProductMap.get(category);
  9. if (!categoryProductList) {
  10. categoryProductList = [];
  11. }
  12. categoryProductList.push(product);
  13. categoryProductMap.set(category, categoryProductList);
  14. });
  15. // 获取类别列表
  16. const categoryList = Array.from(categoryProductMap.keys());
  17. // 菜单选中索引
  18. const [current, setCurrent] = useState(0);
  19. /**
  20. * 内容引用
  21. */
  22. const contentRef = useRef();
  23. /**
  24. * 当左侧菜单点击时候
  25. */
  26. const onMenuClick = (idx) => {
  27. if (idx !== current) {
  28. // 内容自动滚动到对应菜单位置
  29. contentRef.current.scrollTop = height.slice(0, idx).reduce((a, b) => a + b, 0);
  30. setCurrent(idx);
  31. }
  32. }
  33. /**
  34. * 计算右侧商品类别卡片高度
  35. */
  36. const height = [];
  37. const itemHeight = 25;
  38. categoryList.forEach((category, index) => {
  39. var productCnt = categoryProductMap.get(category).length;
  40. height.push((productCnt + 1) * itemHeight); // 0.8 是header高度
  41. });
  42. console.log(height)
  43. /**
  44. * 当右侧内容滚动时候
  45. */
  46. const onContentScroll = () => {
  47. const scrollTop = contentRef.current.scrollTop;
  48. if (current < height.length - 1){
  49. const nextIdx = current + 1;
  50. // 计算下一个位置高度
  51. const nextHeight = height.slice(0, nextIdx).reduce((a, b) => a + b, 0);
  52. console.log('scrollTop', scrollTop, 'nextHeight', nextHeight, 'nextIdx', nextIdx)
  53. if (scrollTop >= nextHeight) {
  54. contentRef.current.scrollTop = nextHeight;
  55. setCurrent(nextIdx);
  56. return;
  57. }
  58. }
  59. if (current > 0) {
  60. const lastIdx = current - 1;
  61. // 计算上一个位置高度
  62. const lastHeight = height.slice(0, lastIdx).reduce((a, b) => a + b, 0);
  63. console.log('scrollTop', scrollTop, 'lastHeight', lastHeight, 'lastIdx', lastIdx)
  64. if (scrollTop <= lastHeight) {
  65. contentRef.current.scrollTop = lastHeight;
  66. setCurrent(lastIdx);
  67. return;
  68. }
  69. }
  70. }
  71. return (
  72. <div className='scroll-menu'>
  73. <div className='menu'>
  74. {
  75. // 菜单列表
  76. categoryList.map((category, index) => {
  77. return (
  78. <div className={"menu-item" + ((index === current )? '-active' : '')}
  79. key={`${index}`} id={`menu-item-${index}`}
  80. onClick={(event) => {
  81. onMenuClick(index)
  82. }}>
  83. {category}
  84. </div>
  85. )
  86. })
  87. }
  88. </div>
  89. <div className='content' ref={contentRef} onScroll={(event) => {
  90. onContentScroll()
  91. }}>
  92. {
  93. categoryList.map((category, index) => {
  94. // 获取类别商品
  95. const productList = categoryProductMap.get(category);
  96. return (
  97. <div key={index}>
  98. <div className='content-item-header' key={`${index}`}
  99. id={`content-item-${index}`} style={{
  100. height: itemHeight
  101. }} >{category}</div>
  102. {
  103. productList.map((product,idx) => {
  104. return <div className='content-item-product'style={{
  105. height: itemHeight
  106. }} key={`${index}-${idx}`} >{product.name}</div>
  107. })
  108. }
  109. </div>
  110. )
  111. })
  112. }
  113. </div>
  114. </div>
  115. )
  116. }
ScrollMenu.css
  1. .scroll-menu {
  2. display: flex;
  3. flex-direction: row;
  4. width: 300px;
  5. height: 100px;
  6. }
  7. .menu{
  8. width: 90px;
  9. height: 100px;
  10. display: flex;
  11. flex-direction: column;
  12. }
  13. .menu-item {
  14. text-align: center;
  15. vertical-align: middle;
  16. }
  17. .menu-item-active {
  18. text-align: center;
  19. vertical-align: middle;
  20. background-color: lightcoral;
  21. }
  22. .content {
  23. width: 210px;
  24. overflow: auto;
  25. }
  26. .content-item-header{
  27. text-align: left;
  28. vertical-align: top;
  29. background-color: lightblue;
  30. }
  31. .content-item-product{
  32. text-align: center;
  33. vertical-align: center;
  34. background-color: lightyellow;
  35. }
App.js
  1. import './App.css';
  2. import {ScrollMenu} from "./component/scroll-menu/ScrollMenu";
  3. const App = ()=> {
  4. const products = [
  5. {
  6. category:'蔬菜',
  7. name:'辣椒'
  8. },
  9. {
  10. category:'蔬菜',
  11. name:'毛豆'
  12. },
  13. {
  14. category:'蔬菜',
  15. name:'芹菜'
  16. },
  17. {
  18. category:'蔬菜',
  19. name:'青菜'
  20. },
  21. {
  22. category:'水果',
  23. name:'苹果'
  24. },
  25. {
  26. category:'水果',
  27. name:'梨'
  28. },
  29. {
  30. category:'水果',
  31. name:'橘子'
  32. }, {
  33. category:'食物',
  34. name:'肉'
  35. }, {
  36. category:'食物',
  37. name:'罐頭'
  38. }
  39. , {
  40. category:'食物',
  41. name:'雞腿'
  42. }
  43. ];
  44. return (
  45. <ScrollMenu products={products}/>
  46. )
  47. }
  48. export default App;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/297621
推荐阅读
相关标签
  

闽ICP备14008679号