组件_AuchorMenu


AuchorMenu组件

可适用场景布局分为两个部分,内容区域和锚点区域,内容区域可上下滚动,同时影响锚点目标区域高亮,锚点区域可点击,影响内容区域滚动到指定区域

组件代码

import React, { useEffect } from 'react';
import { Affix } from 'antd';
import styles from './index.less';

export function Anchormenu(props: {
  menu: { label: string; value: string }[];
  targetId: string;
}) {
  const handelScroll = () => {
    // 不通设备或浏览器版本scrollTop 可能会出现浮点数,而元素的offsetTop肯定是整数,浮点数的一点差距可能会影响下面的判断,因此做兼容处理向上取整
    const targetArea = document.querySelector(props.targetId);
    const scrollTop = Math.ceil(targetArea?.scrollTop as number);
    const li_list = document.querySelectorAll(`ul.${styles.anchor} > li`);
    for (let i = 0; i < props.menu.length; i++) {
      const eleOffsetTop = document.getElementById(
        props.menu[i].value,
      )!.offsetTop;
      let nextEleOffsetTop = 0;
      if (i < props.menu.length - 1) {
        nextEleOffsetTop = document.getElementById(
          props.menu[i + 1].value,
        )!.offsetTop;
        if (i === 0) {
          if (scrollTop < nextEleOffsetTop) {
            li_list.forEach((el) => el.classList.remove(`${styles.active}`));
            li_list[i].classList.add(`${styles.active}`);
          }
        } else {
          if (eleOffsetTop <= scrollTop && scrollTop < nextEleOffsetTop) {
            li_list.forEach((el) => el.classList.remove(`${styles.active}`));
            li_list[i].classList.add(`${styles.active}`);
          }
        }
      } else {
        if (eleOffsetTop <= scrollTop) {
          li_list.forEach((el) => el.classList.remove(`${styles.active}`));
          li_list[i].classList.add(`${styles.active}`);
        }
      }
    }
  };
  useEffect(() => {
    const targetArea = document.querySelector(props.targetId);
    targetArea?.addEventListener('scroll', handelScroll);
    return () => {
      targetArea?.removeEventListener('scroll', handelScroll);
    };
  }, []);

  const targetScroll = (target: string) => {
    const targetEle = document.getElementById(target);
    const targetArea = document.querySelector(props.targetId);
    targetArea?.scrollTo({ top: targetEle!.offsetTop, behavior: 'smooth' });
  };

  return (
    <Affix>
      <ul
        style={{
          width: 14,
          position: 'absolute',
          right: 20,
          top: 8,
          textAlign: 'center',
        }}
      >
        {props?.menu?.map((item, index) => {
          if (index === 0) {
            return (
              <li
                onClick={() => targetScroll(item.value)}
                className={styles.active}
                key={item.value}
              >
                <a>{item.label}</a>
              </li>
            );
          }
          return (
            <li
              key={item.value}
              onClick={() => {
                targetScroll(item.value);
              }}
            >
              <a>{item.label}</a>
            </li>
          );
        })}
      </ul>
    </Affix>
  );
}

样式代码

.anchor {
  margin: 0;
  padding: 0;
  list-style: none;

  li {
    height: 17px;
    line-height: 17px;
    font-size: 12px;
  }

  a {
    color: rgb(0 0 0 / 65%);
  }
}

.anchor .active {
  a {
    color: #3751ff;
  }
}

文章作者: 洪大俊
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 洪大俊 !
评论
  目录