admin管理员组

文章数量:1394143

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?

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?

Share asked Feb 3, 2018 at 8:11 YavorYavor 1491 silver badge15 bronze badges 1
  • makotot.github.io/react-scrollspy - Using this quick easy plugin can help anyone looking for this info – brooksrelyt Commented Jun 17, 2019 at 18:35
Add a ment  | 

5 Answers 5

Reset to default 3

Link provides two options for adding styles to the active link:

activeStyle — a style object that will only be applied when the current item is active

activeClassName — a class name that will only be added to the Link when the current item is active

Follow official docs: https://www.gatsbyjs/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>
)

You can set the activeStyle or activeClassName prop to add styling attributes to the rendered element when it matches the current URL, and Gatsby also supports React Router's props exact, strict, isActive, and location. If any of these props are set, then React Router's NavLink ponent will be used instead of the default Link.

Example:

import Link from "gatsby-link"

render () {
 <div>
  <Link
   to="/another-page/"
   activeStyle={{
     color: 'red'
   }}
   innerRef={(el) => { this.myLink = el }}
  >
   Another page
  </Link>
 </div>
}

Visit https://github./gatsbyjs/gatsby/tree/master/packages/gatsby-link

I did it the hard way as I couldn't find another solution:

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;

As brooksrelyt noted in the ment above, you can easily use react-scrollspry to add a unique class name to the hash link that has been clicked. Here is how I use it:

import { Text } from 'rebass/styled-ponents'
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>

In short, you wrap your links with a Scrollspy ponent and include (at the very least) two mandatory props: items and currentClassName.

  • items is an array of the hash names (without the hash character)
  • currentClassName is the name of the class you want to add to the selected link.

NOTE: I included the rebass Text ponent because it did not work properly for me when I used a simple div. You should read the documentation for how to use it in your particular case - as there are other props that may be needed in different situations.

I did a website some weeks ago with this feature. I created a function to know what section are the active and put it on the state in react. This function is called everytime the user move the scrollbar.

In render, I change de className of the elements depending the element of the state. In every section/element that i want to track I put an ID.

Util function:

/**
 * 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
  };
}

On React ponent:

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

ponentWillUnmount() {
    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>;
    });
     ...
}

本文标签: javascriptActive classnames in menu on a onepage website using GatsbyJSStack Overflow