文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

React实现锚点跳转组件附带吸顶效果的示例代码

2023-01-05 09:00

关注

React实现锚点跳转组件附带吸顶效果

import React, { useRef, useState, useEffect } from 'react';
import styles from './index.less';
import classnames from 'classnames';

function AnchorTabber(props) {
  const root = useRef(null);
  const header = useRef(null);
  const {
    attrbute = 'data-anchor',
    offsetY = 60,
    list = [],
    initialKey = list[0]?.key,
    children,
  } = props;
  const [state, setState] = useState({
    activeKey: initialKey,
  });
  const [key2Bottom, setKey2Bottom] = useState({
    key2Bottom: {},
  });
  
  const scrollElement = document.querySelector('#root').firstChild;
  function scrollTo(key) {
    // if(!scrollElement) {
    //   scrollElement = document.querySelector('#root').firstChild;
    // }

    const attribute = attrbute;
    
    const targetEl = root.current?.querySelector(`[${attribute}=${key}]`);
    if (targetEl) {
      const clientRect = targetEl.getBoundingClientRect();
      const top = scrollElement.scrollTop + clientRect.top - offsetY;
      scrollElement.scrollTo({
        top,
        behavior: 'smooth',
      });
      // targetEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  }

  function updateElementsPosition() {
    const elements = document.querySelectorAll(`[${attrbute}]`);
    Array.from(elements).forEach(element => {
      const targetAttr = element.getAttribute(`${attrbute}`);
      const clientRect = element.getBoundingClientRect();

      const bottom = clientRect.top + scrollElement.scrollTop;
      key2Bottom[targetAttr] = bottom;
    });
    setKey2Bottom(key2Bottom);
  }

  function handleScroll() {
    const top = scrollElement.scrollTop + offsetY;
    // eslint-disable-next-line no-unused-vars
    const target = Object.entries(key2Bottom)
      .sort(([, v1], [, v2]) => v2 - v1)
      .find(([, v]) => v <= top);
    if (target) {
      setState({
        activeKey: target[0],
      });
    }
  }

  useEffect(() => {
    updateElementsPosition();
    // document.addEventListener('touchstart', updateElementsPosition);
    scrollElement.addEventListener('scroll', handleScroll);
    return () => {
      // document.removeEventListener('touchstart', updateElementsPosition);
      scrollElement.removeEventListener('scroll', handleScroll);
    };
  });

  function handleItemClick(tabber) {
    scrollTo(tabber.key);
  }

  function render() {
    let { activeKey } = state;
    if(typeof(activeKey) === "undefined") {
      activeKey = initialKey
    }
    
    return (
      <div className={styles.mAnchorTabber}>
        <div className={styles.header} ref={header}>
          {list?.map(tabber => (
            <div
              className={classnames(styles.item, { [styles.active]: activeKey === tabber.key })}
              onClick={() => handleItemClick(tabber)}
            >
              {tabber.name}
            </div>
          ))}
        </div>
        <div className={styles.container} ref={root}>
          {children}
        </div>
      </div>
    );
  }

  return render();
}


export default AnchorTabber;

对应样式(less)

.mAnchorTabber {
  .header {
    display: flex;
    align-items: center;
    position: sticky;
    top: 0;
    height: .len(46) [];
    box-sizing: border-box;
    box-shadow: 0 .len(2) [] .len(2) [] .len(1) [] #c4c4c4;
    background-color: @basecolor;
    .item {
      height: 100%;
      flex-grow: 1;
      flex-shrink: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: 400;
      font-size: @font-size-base-normal;
      line-height: .len(20) [];
      &.active {
        background-color: @bgc-product-detail;
        color: @basecolor;
      }
    }
  }
}

.len(46) []这个改成对应 px单位即可,本单位是为了移动端适配转换

测试test

对应测试文件

import React from 'react';
import { connect } from 'dva';

import AnchorTabber from '@/components/m/AnchorTabber';

@connect(({ common }) => ({
  common,
}))
class ApplicationsRecord extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [
        {
          name: 'test1',
          key: 'test1',
        },
        {
          name: 'test2',
          key: 'test2',
        },
        {
          name: 'test3',
          key: 'test3',
        },
      ],
    };
  }

  render() {
    const { list } = this.state;
    const index2Attr = {
      0: 'test1',
      100: 'test2',
      200: 'test3',
    };
    return (
      <AnchorTabber list={list}>
        <ul className="list">
          {new Array(1000).fill(null).map((_item, index) => (
            <li data-anchor={index2Attr[index]}>{index}</li>
          ))}
        </ul>
      </AnchorTabber>
    );
  }
}
export default ApplicationsRecord;

到此这篇关于React实现锚点跳转组件附带吸顶效果的示例代码的文章就介绍到这了,更多相关React锚点跳转组件附带吸顶效果内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯