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

 更新时间:2023年01月05日 08:52:24   作者:绘绘~  
这篇文章主要为大家详细介绍了React如何实现移动端锚点跳转组件附带吸顶效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下

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: {},
  });
  /** @type { HTMLDivElement } */
  const scrollElement = document.querySelector('#root').firstChild;
  function scrollTo(key) {
    // if(!scrollElement) {
    //   scrollElement = document.querySelector('#root').firstChild;
    // }

    const attribute = attrbute;
    /** @type { HTMLDivElement } */
    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锚点跳转组件附带吸顶效果内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React实现导入导出Excel文件

    React实现导入导出Excel文件

    本文主要介绍了React实现导入导出Excel文件,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • react+ts实现简单jira项目的最佳实践记录

    react+ts实现简单jira项目的最佳实践记录

    这篇文章主要介绍了react+ts实现简单jira项目,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • 利用React-router+Webpack快速构建react程序

    利用React-router+Webpack快速构建react程序

    目前 React、Webpack 等技术如火如荼,你是不是还在愁苦如何把这些杂乱的知识怎么学习一下,开启一段新的前端开发之路呢?那么这篇将给大家运用示例代码详细的介绍使用React-router和Webpack如何快速构建一个react程序,感兴趣的朋友们下面来一起看看吧。
    2016-10-10
  • 解决React报错Cannot assign to 'current' because it is a read-only property

    解决React报错Cannot assign to 'current'

    这篇文章主要为大家介绍了React报错Cannot assign to 'current' because it is a read-only property的解决方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 封装一个最简单ErrorBoundary组件处理react异常

    封装一个最简单ErrorBoundary组件处理react异常

    这篇文章主要介绍了一个处理react异常的ErrorBoundary组件,简单实用,代码详细,对这个组件感兴趣的朋友可以参考下
    2021-04-04
  • React实现一个倒计时hook组件实战示例

    React实现一个倒计时hook组件实战示例

    这篇文章主要为大家介绍了React实现一个倒计时hook组件,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 基于React实现倒计时功能

    基于React实现倒计时功能

    这篇文章主要为大家详细介绍了如何基于React实现倒计时功能,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下
    2024-02-02
  • 深入了解React中的虚拟DOM

    深入了解React中的虚拟DOM

    欢迎来到今天的探险之旅!在这篇博客中,我们将深入了解 React 中神奇的虚拟DOM,并通过一个简单的例子来揭开其神秘面纱,文中通过代码示例也讲解非常详细,感兴趣的朋友可以参考下
    2024-01-01
  • React与Redux之数组处理讲解

    React与Redux之数组处理讲解

    这篇文章主要介绍了React与Redux之数组处理讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • React-router v4 路由配置方法小结

    React-router v4 路由配置方法小结

    本篇文章主要介绍了React-router v4 路由配置方法小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08

最新评论