简体   繁体   English

React.js 16.8 底部导航在滚动后固定到顶部

[英]React.js 16.8 Bottom Nav fixed to top after scroll

The Navbar is currently positioned at the bottom of the view port and it need's to become fixed to the top as I scroll.导航栏当前位于视口的底部,当我滚动时它需要固定在顶部。 I have tried mixing in jquery because that's how most tutorials that I have found use.我已经尝试在 jquery 中混合,因为这是我发现的大多数教程的使用方式。 If anyone has a solution using react.js I would really appreciate it.如果有人有使用 react.js 的解决方案,我将不胜感激。 I currently have this:我目前有这个:

const Navbar = () => {

  const main = document.querySelector('.home');
  const nav = document.querySelector('.navbar');


  window.onscroll = function () {

      if (window.pageYOffset > (main.offsetHeight - nav.offsetHeight)) {
          nav.classList.remove('bottom-nav');
          nav.classList.add('nav');
      } else {
          nav.classList.add('bottom-nav');
          nav.classList.remove('nav');

      }
  }
  return(
    <nav className="navbar">
        <ul>
            <li><a href="#about">About</a></li>
            <li><a href="#resume">Resume</a></li>
            <li><a href="#projects">Projects</a></li>
            <li><a href="#contact">Contact</a></li>
        </ul>
    </nav>
  )
}

This is what the scss looks like:这是scss的样子:

.top-nav {
    position: fixed;
    top: 0;
}

.bottom-nav {
    position: absolute;
    bottom: 0;
}

and other styling under just the html tag nav .以及仅在 html 标签nav下的其他样式。

The error that I am getting is:我得到的错误是:

TypeError: Cannot read property 'offsetHeight' of null
Navbar.window.onscroll
src/components/Navbar.jsx:12
   9 | 
  10 | window.onscroll = function () {
  11 | 
> 12 |     if (window.pageYOffset > (main.offsetHeight - nav.offsetHeight)) {
     | ^  13 |         nav.classList.remove('bottom-nav');
  14 |         nav.classList.add('nav');
  15 |     } else {

This is happening since you are attaching scroll handler before the component is actually mounted.发生这种情况是因为您在实际安装组件之前附加了滚动处理程序。 Move your scroll handler to App.js or parent component and initialize it after component has mounted.将滚动处理程序移动到 App.js 或父组件,并在组件安装后对其进行初始化。 For this, you can use componentDidMount life-cycle hook if it is a class based component or useEffect hook if it is a functional component.为此,如果它是基于 class 的组件,则可以使用componentDidMount生命周期挂钩;如果它是功能组件,则可以使用useEffect挂钩。

Also, the better "react" way would be using props to update components class.此外,更好的“反应”方式是使用props更新组件 class。 Give your navbar component any prop to handle toggling of class.为您的navbar组件提供任何prop来处理 class 的切换。 Let's say we add a new prop sticky to navbar .假设我们向sticky添加了一个新的 props navbar Then we can update it like this:然后我们可以像这样更新它:

const Navbar = (props) => {
  
  // we can directly use the prop value to update our classes

  return(
    <nav className={`navbar ${props.sticky ? 'nav' : 'bottom-nav'}`}>
      <ul>
        <li><a href="#about">About</a></li>
        <li><a href="#resume">Resume</a></li>
        <li><a href="#projects">Projects</a></li>
        <li><a href="#contact">Contact</a></li>
      </ul>
     </nav>
   )
 }
 

Then in our parent component we can maintain a state to track when the navbar component's class needs to be updated.然后在我们的父组件中,我们可以维护一个 state 来跟踪导航栏组件的 class 何时需要更新。 We then pass the state down as prop to the child component.然后我们将 state 作为道具传递给子组件。

--------------------
  App.js
--------------------

/**
 * Class based approach
 **/

constructor() {
   this.main = null;
   this.nav = null;
   this.state = {
      stickyHeader: false
   }
}


componentDidMount() { 
   // we can safely store these values in instance variable
   // so that we just have to query the DOM once
   this.main = document.querySelector('.home');
   this.nav = document.querySelector('.navbar');

   window.onscroll = function () {
   
   if (window.pageYOffset > (main.offsetHeight - nav.offsetHeight)) {
      this.setState({stickyHeader: true});
   } else {
      this.setState({stickyHeader: false});
    }
  }
}

render() {
   ....
   <NavBar sticky={this.state.stickyHeader} />
   
}

/**
 * Functional component approach
 **/

// useRef value remains constant across render
// so we use it to define our variables
const main = useRef(null);
const nav = useRef(null);

// local state to keep track of navbar updates
const [stickyHeader, updateStickyHeader] = useState(false);

useEffect(() => { 
  // on mount query and update refs value
  main.current = document.querySelector('.home');
  nav.current = document.querySelector('.navbar');

  window.onscroll = function () {

   if (window.pageYOffset > (main.current.offsetHeight - nav.current.offsetHeight)) {
      updateStickyHeader(true);
   } else {
      updateStickyHeader(false);
    }
  }

}, [])

return (
  <>
    ...
    <NavBar sticky={this.state.stickyHeader} />
  </>

I would recommend you to read more about React lifecycle to understand better.我建议您阅读有关 React生命周期的更多信息以更好地理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM