javascript 如何在 React 中使用 scrollIntoView?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46677725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 06:51:40  来源:igfitidea点击:

How to use scrollIntoView in React?

javascriptreactjs

提问by jcs1977

I am trying to use links in my header to scroll to different parts of my App with scrollIntoView. The header is a child of App. I am getting a TypeError saying the variable I am trying to save the id to is undefined. Can someone please help me to determine what I am doing wrong? I think I may have to use ComponentDidMount, but I'm not sure how to do it, if that is even the fix. I am going to have to do this with all my header links.

我正在尝试使用标题中的链接通过 scrollIntoView 滚动到我的应用程序的不同部分。标头是 App 的子项。我收到一个 TypeError,说我试图将 id 保存到的变量未定义。有人可以帮我确定我做错了什么吗?我想我可能不得不使用 ComponentDidMount,但我不知道该怎么做,如果那是修复的话。我将不得不用我所有的标题链接来做这件事。

//ERROR bundle.js:152 Uncaught TypeError: Cannot read property 'scrollIntoView' of null at App.getScrollLocations (bundle.js:152) at onClick (bundle.js:19957) at Object.ReactErrorUtils.invokeGuardedCallback (bundle.js:4660) at executeDispatch (bundle.js:4460) at Object.executeDispatchesInOrder (bundle.js:4483) at executeDispatchesAndRelease (bundle.js:3913) at executeDispatchesAndReleaseTopLevel (bundle.js:3924) at Array.forEach () at forEachAccumulated (bundle.js:4760) at Object.processEventQueue (bundle.js:4129) ///////

//ERROR bundle.js:152 Uncaught TypeError: 无法在 App.getScrollLocations (bundle.js:152) at onClick (bundle.js:19957) at Object.ReactErrorUtils.invokeGuardedCallback (bundle.js: 4660) at executeDispatch (bundle.js:4460) at Object.executeDispatchesInOrder (bundle.js:4483) at executeDispatchesAndRelease (bundle.js:3913) at executeDispatchesAndReleaseTopLevel (bundle.js:3924) at Array.forEach () at Array.forEach () .js:4760) 在 Object.processEventQueue (bundle.js:4129) ///////

//App

//应用程序

class App extends Component {
  constructor(props) {
    super(props);

    this.closeModal = this.closeModal.bind(this);
    this.openModal = this.openModal.bind(this);
    this.getScrollLocations = this.getScrollLocations.bind(this);

    this.state = {
      open: false,
      projects: Service,
      selectedProject: Service[0]
    }
  }

  closeModal(event) {
    this.setState({open: false});
  }

  openModal(project) {
    this.setState({
      open: true,
      selectedProject: project
    });
  }
    ///////////// scroll function //////////////
  getScrollLocations() {
    const whatIDo = document.getElementById('.whatIdo');
    console.log(whatIDo)
    whatIDo.scrollIntoView();
  }

  render() {
    const show = {
      display: 'block'
    };
    const hide = {
      display: 'none'
    };
    return (
      <div>
        <div style={this.state.open === false ? hide : show}>
          <Modal
            value={this.state.open}
            closeModal={this.closeModal}
            project={this.state.selectedProject}
          />
        </div>
        <Header
          //////////// FUNCTION PASSED TO HEADER ///////////////
          getScrollLocations={this.getScrollLocations}
        />
        <Intro />
        /////////////// ELEMENT I AM TARGETING /////////////////
        <WhatIDo id="whatIDo" />
        <WhoIAm />
        <Gallery
          value={this.state.open}
          projects={this.state.projects}
          openModal={this.openModal}
        />
        <Contact />
        <Footer />
      </div>
    );
  }
}

//Header

//标题

const header = (props) => {
  console.log(props);
  return (
    <div className="header">
      <div className="header-name">
         XXXXXXX XXXXXXX
      </div>

      <div className="header-links">
        <ul>
          <li>Intro</li>
          <li
            ///////////// FUNCTION CALL ON CLICK /////////////////
            onClick={() => props.getScrollLocations()}
          >What I do</li>
          <li>Who I am</li>
          <li>My Work</li>
          <li>Contact</li>
        </ul>
      </div>
    </div>
  )
}

回答by Anthony Cregan

I used the following module to achieve this in react:

我在反应中使用以下模块来实现这一点:

https://www.npmjs.com/package/scroll-into-view-if-needed

https://www.npmjs.com/package/scroll-into-view-if-needed

It works much as you'd expect using in-page anchor links and can be used with react-router without problems.

它的工作方式与您期望的使用页内锚链接非常相​​似,并且可以毫无问题地与 react-router 一起使用。

import React from 'react';
import PropTypes from 'prop-types';

import scrollIntoViewIfNeeded from 'scroll-into-view-if-needed';

/*
SCROLL INTO VIEW

Purpose:
  This modular component enables hash links
  eg. (www.xyz.com/somepage#someID)
  and plays nice with react router 4

Usage:
  Wrap this component around a single div with an ID

Example:
  <ScrollIntoView  id={this.props.location.hash}>
    <div id="someID">
      ... loads of content...
    </div>
  </ScrollIntoView>

  <a href="/somepage#someID"> IN-PAGE ANCHOR </a>

 */

class ScrollIntoView extends React.Component {


  componentDidMount() {
    this.scroll();
  }

  componentDidUpdate() {
    this.scroll();
  }

  scroll() {
    const { id } = this.props;
    //console.log('ID is: '+id);
    if (!id) {
      return;
    }
    const element = document.querySelector(id);
    if (element) {
      // this just jumps to the element
      // see support:
      //element.scrollIntoView({block: "end", behavior: "smooth"});

      //If Firefox...
      if (navigator.userAgent.indexOf("Firefox") > 0) {
        //...use native smooth scrolling.
        element.scrollIntoView({block: "end", behavior: "smooth"});
      // If its any other browser, use custom polyfill...
      }else{
        //... luckily I have this handy polyfill...
        scrollIntoViewIfNeeded(element, false, {
          duration: 150
        });
        //  (?■_■
      }
    }
  }

  render() {
    return this.props.children;
  }
}
ScrollIntoView.propTypes = {
  id: PropTypes.string.isRequired,
  children: PropTypes.oneOfType([
    PropTypes.array.isRequired,
    PropTypes.object.isRequired
  ])
};
export default ScrollIntoView;

Here is an example of that in action: https://anthonycregan.co.uk/portfolio

这是一个实际的例子:https: //anthonycregan.co.uk/portfolio