最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin4浏览0评论

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>;
    });
     ...
}
发布评论

评论列表(0)

  1. 暂无评论