zoukankan      html  css  js  c++  java
  • React PC端悬浮锚点吸顶导航

    需求描述

    • 实现PC端吸顶导航

    实现分析

    • 先采用absolute绝对定位
    • 滚动超过锚点导航时,修改该导航定位为fixed

    效果预览

    实现方法

    /** 锚点导航*/
    import React from "react";
    import styles from "./index.less";
    import classnames from "classnames";
    import { ActiveType } from "@17zwd/fe-egg-factory-page/detail/type";
    
    interface PageState {
      // 目录激活项
      activeItem?: string;
      // 是否吸顶
      isSticky?: boolean;
    }
    
    class AnchorNav extends React.Component<any, PageState> {
      private scrollTimer;
      constructor(props) {
        super(props);
        this.state = {
          activeItem: ActiveType.baseInfo,
          isSticky: false,
        };
      }
    
      componentDidMount(): void {
        // 绑定页面滚动事件
        window.addEventListener("scroll", this.onPageScroll);
      }
    
      componentWillUnmount(): void {
        // 解绑页面滚动事件
        window.removeEventListener("scroll", this.onPageScroll);
      }
    
      compare = (prop) => {
        return function (a, b) {
          const value1 = a[prop];
          const value2 = b[prop];
          return value1 - value2;
        };
      };
    
      // 页面滚动事件
      onPageScroll = (): void => {
        if (this.scrollTimer) {
          clearTimeout(this.scrollTimer);
        }
        this.scrollTimer = setTimeout(() => {
          // 吸顶
          const firstItemTop = document
            .getElementById(ActiveType.baseInfo)
            ?.getBoundingClientRect().top;
          if (firstItemTop && firstItemTop < 0) {
            this.setState({
              isSticky: true,
            });
          } else {
            this.setState({
              isSticky: false,
            });
          }
          // 动态高亮
          const viewTops: Array<any> = [];
          for (const i in ActiveType) {
            const id = ActiveType[i];
            const ele = document.getElementById(id);
            if (!ele) return;
            const top = ele?.getBoundingClientRect().top;
            if (top < 0) continue;
            viewTops.push({
              id,
              top,
            });
          }
          viewTops.sort(this.compare("top"));
          this.setState({
            activeItem: viewTops[0]?.id,
          });
        }, 90);
      };
    
      //跳转到的锚点
      onScrollToAnchor = (activeItem: string): void => {
        if (activeItem) {
          // 找到锚点
          const anchorElement = document.getElementById(activeItem);
          // 如果对应id的锚点存在,就跳转到锚点
          if (anchorElement) {
            anchorElement.scrollIntoView({ block: "start", behavior: "smooth" });
            this.setState({
              activeItem,
            });
          }
        }
      };
    
      getItemName = (en: string): string => {
        let res = "";
        switch (en) {
          case ActiveType.baseInfo:
            res = "基础信息";
            break;
          case ActiveType.certify:
            res = "资质认证";
            break;
          case ActiveType.overview:
            res = "综合概览";
            break;
          case ActiveType.remark:
            res = "工厂简介";
            break;
          case ActiveType.pics:
            res = "工厂实拍";
            break;
          case ActiveType.product:
            res = "产品案例";
            break;
          default:
            break;
        }
        return res;
      };
    
      renderItem = (): JSX.Element => {
        const { activeItem } = this.state;
        const items: Array<any> = [];
        for (const i in ActiveType) {
          const element = ActiveType[i];
          if (element) {
            items.push(element);
          }
        }
        return (
          <React.Fragment>
            {items.map((item, index) => {
              return (
                <li
                  key={index}
                  onClick={() => this.onScrollToAnchor(item)}
                  className={activeItem === item ? styles.active : ""}
                >
                  <span
                    className={classnames(styles.anchorItem, styles.anchorNoBorder)}
                  >
                    {this.getItemName(item)}
                  </span>
                </li>
              );
            })}
          </React.Fragment>
        );
      };
    
      render(): JSX.Element {
        const { isSticky } = this.state;
        return (
          <React.Fragment>
            <div
              className={classnames(
                styles.mainAnchor,
                isSticky ? styles.positionSticky : styles.positionAbsolute
              )}
            >
              <ul className={styles.anchorList}>{this.renderItem()}</ul>
            </div>
          </React.Fragment>
        );
      }
    }
    
    export default AnchorNav;
    
    
    @import "@/less/mixin.less";
    
    // 导航
    .positionSticky {
      position: fixed;
      margin-left: -124px;
      z-index: 1;
    }
    .positionAbsolute {
      position: absolute;
      left: -124px;
    }
    .mainAnchor {
      top: 0;
       124px;
      .anchorList {
        margin-bottom: 0;
        padding: 0 24px;
         112px;
        box-sizing: border-box;
        background-color: @background-secondary-color;
        > li {
          position: relative;
          color: @text-thrid-color;
          transition: all 0.2s linear;
          &:hover {
            color: @main-primary-color;
          }
        }
        .anchorItem {
          display: block;
          padding: 16px 0;
          height: 53px;
          font-size: 16px;
          line-height: 21px;
          box-sizing: border-box;
          border-top: solid 1px @border-primary-color;
          cursor: pointer;
        }
        .anchorNoBorder {
          border-top: none;
        }
        .active {
          color: @main-primary-color;
          &::before {
            position: absolute;
            content: "";
            left: -14px;
            top: 24px;
             6px;
            height: 6px;
            border-radius: 50%;
            background-color: @main-primary-color;
          }
        }
      }
      .navBox {
        visibility: hidden;
      }
    }
    
    
  • 相关阅读:
    Java快速开发框架LML功能菜单管理
    性能测试知多少性能需求分析
    C++学习的方法以及四大名著
    .NET Micro Framework官方库+Controller Area Network
    PostgreSQL学习笔记
    幻风阁|kent.zhu'sBlog对google阅读器共享设计的再讨论
    【数据库事务日志碎片原理分析与方案】分析篇
    Windows 8 RC升级到RTM很顺利
    http://www.cnblogs.com/oneday/archive/2012/08/16/2643039.html
    Visual Studio 2012 Ultimate RTM 体验
  • 原文地址:https://www.cnblogs.com/KevinTseng/p/14597805.html
Copyright © 2011-2022 走看看