Active classnames in menu on a one-page website using GatsbyJS

时间:2018-02-03 08:11:15

标签: javascript reactjs gatsby

I'm using a single page template with GatsbyJS on which the menu scrolls to the different sections of the same page (#home, #about, #portfolio, etc). Is there a way to set an active classname on the links, highlighting the link the user is on?

5 个答案:

答案 0 :(得分:1)

您可以设置activeStyleactiveClassName道具,以便在与当前网址匹配时为渲染元素添加样式属性,而Gatsby也支持React Router的道具exact,{{1 },strictisActive。如果设置了任何这些道具,则将使用React Router的location组件而不是默认链接。

示例:

NavLink

访问enter image description here

答案 1 :(得分:1)

我努力工作,因为我无法找到另一种解决方案:

import React, { Component } from 'react';
import './Menu.css';

class Menu extends Component {

    constructor(props) {
        super(props)
        this.state = {
            home: true,
            about: false,
            portfolio: false
        }
        this.handleActive = this.handleActive.bind(this)
    }

    handleActive(button) {
        switch (button) {
            case 'home':
                this.setState({
                    home: true,
                    about: false,
                    portfolio: false
                });
                break;
            case 'about':
                this.setState({
                    home: false,
                    about: true,
                    portfolio: false
                });
                break;
            case 'portfolio':
                this.setState({
                    home: false,
                    about: false,
                    portfolio: true
                });
                break;
            default: break;
        }
    }

    render() {
        return (
            <div id="nav-wrap">
                <nav>
                    <input type="checkbox" id="checkbox1" />
                    <label htmlFor="checkbox1">
                        <ul className="menu first">
                            <li><a
                                className={this.state.home ? 'active' : null}
                                onClick={() => this.handleActive('home')}
                                href="#home">HOME</a></li>
                            <li><a
                                className={this.state.about ? 'active' : null}
                                onClick={() => this.handleActive('about')}
                                href="#about">ABOUT МЕ
            </a></li>
                            <li><a
                                className={this.state.portfolio ? 'active' : null}
                                onClick={() => this.handleActive('portfolio')}
                                href="#portfolio">PORTFOLIO</a></li>
                        </ul>
                        <span className="toggle">☰</span>
                    </label>
                </nav>

            </div>
        )
    }
}

export default Menu;

答案 2 :(得分:0)

几周前,我做了一个网站,使用此功能。我创建了一个函数来知道哪个部分是活动的,并将其置于状态中。每当用户移动滚动条时,都会调用此功能。

在渲染中,我根据状态元素更改元素的de className。在我要跟踪的每个部分/元素中,我都添加了一个ID。

使用功能:

/**
 * Helper function to get an element's exact position
 * @param  {element}  element
 * @return {x,y}
 */
export function getPosition(el) {
  var xPos = 0;
  var yPos = 0;

  while (el) {
    if (el.tagName == "BODY") {
      // deal with browser quirks with body/window/document and page scroll
      var xScroll = el.scrollLeft || document.documentElement.scrollLeft;
      var yScroll = el.scrollTop || document.documentElement.scrollTop;

      xPos += (el.offsetLeft - xScroll + el.clientLeft);
      yPos += (el.offsetTop - yScroll + el.clientTop);
    } else {
      // for all other non-BODY elements
      xPos += (el.offsetLeft - el.scrollLeft + el.clientLeft);
      yPos += (el.offsetTop - el.scrollTop + el.clientTop);
    }

    el = el.offsetParent;
  }
  return {
    x: xPos,
    y: yPos
  };
}

在React组件上:

componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
    this.handleScroll();
}

componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
}

handleScroll() {
    const {inAnimation} = this.state;

    let activeElement = false;

    this.props.data.items.forEach((value,i) => {
        let element = document.getElementById(value.url.substring(1));
        if(getPosition(element).y <= 0){
            activeElement = value.url;
        }
    });
    this.setState({
        activeElement
    });
    }
}
render(){
     ...
     items.map((item, i) => {
        return <li key={i}>
            <a className={'menu-item' + (activeElement == item.url ? ' active': '')}>{item.title}</a>
        </li>;
    });
     ...
}

答案 3 :(得分:0)

链接提供了两个用于将样式添加到活动链接的选项:

activeStyle —一种样式对象,仅在当前项目处于活动状态时才会应用

activeClassName —仅在当前项目处于活动状态时才会添加到链接中的类名

关注官方文档https://www.gatsbyjs.org/docs/gatsby-link/#add-custom-styles-for-the-currently-active-link

import React from "react"
import { Link } from "gatsby"

const SiteNavigation = () => (
  <nav>
    <Link
      to="/"
      {/* This assumes the `active` class is defined in your CSS */}
      activeClassName="active"
    >
      Home
    </Link>
    <Link
      to="/about/"
      activeStyle={{ color: "red" }}
    >
      About
    </Link>
  </nav>
)

答案 4 :(得分:0)

如上面评论中的brooksrelyt所述,您可以轻松地使用react-scrollspry将唯一的类名添加到已单击的哈希链接。这是我的用法:

import { Text } from 'rebass/styled-components'
import Scrollspy from 'react-scrollspy'

  <Scrollspy
    items={['home', 'features', 'faq']}
    currentClassName="isCurrent"
  >
    <Link to="#home">Home</Link>
    <Link to="#features">Features</Link>
    <Link to="#faq">FAQ</Link>
  </Scrollspy>

  <Text id="home">Home</Text>
  <Text id="features" mt={'400vh'}>Features</Text>
  <Text id="faq" mt={'150vh'}>FAQ</Text>

简而言之,您使用Scrollspy组件包装链接,并(至少)包括两个强制性道具:itemscurrentClassName

  • items是哈希名称的数组(不包含哈希字符)
  • currentClassName是您要添加到所选链接的类的名称。

注意:我包括了rebass文本组件,因为当我使用简单的div时,它对我来说无法正常工作。您应read the documentation了解如何在特定情况下使用它-因为在不同情况下可能还需要其他道具。