如何滚动到元素?


181

我有一个聊天小部件,每次向上滚动时,它都会拉出一系列消息。我现在面临的问题是加载消息时滑块固定在顶部。我希望它专注于上一个数组中的最后一个索引元素。我发现可以通过传递索引来创建动态引用,但是我还需要知道使用哪种滚动功能来实现这一点

 handleScrollToElement(event) {
    const tesNode = ReactDOM.findDOMNode(this.refs.test)
    if (some_logic){
      //scroll to testNode      
    }
  }

  render() {

    return (
      <div>
        <div ref="test"></div>
      </div>)
  }

1
对于捆绑的解决方案:npmjs.com/package/react-scroll-to-component
tokland

Answers:


301

React 16.8 +,功能组件

import React, { useRef } from 'react'

const scrollToRef = (ref) => window.scrollTo(0, ref.current.offsetTop)   
// General scroll to element function

const ScrollDemo = () => {

   const myRef = useRef(null)
   const executeScroll = () => scrollToRef(myRef)

   return (
      <> 
         <div ref={myRef}>I wanna be seen</div> 
         <button onClick={executeScroll}> Click to scroll </button> 
      </>
   )
}

单击此处,获得有关StackBlits的完整演示

React 16.3 +,Class组件

class ReadyToScroll extends Component {

    constructor(props) {
        super(props)
        this.myRef = React.createRef()  
    }

    render() {
        return <div ref={this.myRef}></div> 
    }  

    scrollToMyRef = () => window.scrollTo(0, this.myRef.current.offsetTop)   
    // run this method to execute scrolling. 

}

类组件-Ref回调

class ReadyToScroll extends Component {
    myRef=null
    // Optional

    render() {
        return <div ref={ (ref) => this.myRef=ref }></div>
    } 

    scrollToMyRef = () => window.scrollTo(0, this.myRef.offsetTop)
    // run this method to execute scrolling. 
}

不要使用字符串引用。

字符串引用会损害性能,不可组合且即将淘汰(2018年8月)。

字符串引用存在一些问题,被认为是旧问题,并且很可能在将来的发行版中被删除。[官方React文档]

资源1 资源2

可选:平滑滚动动画

/* css */
html {
    scroll-behavior: smooth;
}

将ref传递给孩子

我们希望ref附加到dom元素上,而不是附加到react组件上。因此,当将其传递给子组件时,我们无法命名prop ref。

const MyComponent = () => {
    const myRef = useRef(null)
    return <ChildComp refProp={myRef}></ChildComp>
} 

然后将ref prop附加到dom元素。

const ChildComp = (props) => {
    return <div ref={props.refProp} />
}

5
window.scrollTo(0, offsetTop)是目前浏览器中更好的支持,是一个更好的选择
MoMo

1
可以确保您在示例中保持一致。我们从myRef开始,从domRef开始,以tesNode?结尾。这非常令人困惑
路易·莱科克

4
这个事实显而易见,但是重要的是要提到这仅适用于本机DOM元素,而不仅适用于任何React组件。
jpunk11 '18

1
@ jpunk11我刚刚更新了答案。更新后的答案说明了如何滚动到子类组件中的dom元素。
本·卡尔普

2
@SimonFranzen看一下我最新的答案-TLDR-类组件案例。调用scrollToMyRef时,它将滚动到您将引用附加到的子级。您可以将方法传递给另一个子组件,然后从那里触发它。
本·卡尔普

55

这对我有用

this.anyRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' })

编辑:我想根据评论对此进行扩展。

const scrollTo = (ref) => {
  if (ref /* + other conditions */) {
    ref.scrollIntoView({ behavior: 'smooth', block: 'start' })
  }
}

<div ref={scrollTo}>Item</div>

1
放在哪里
su_sundariya

在生命周期方法或构造函数中
su_sundariya

1
奇迹般有效。以上都不是对我不起作用,应该接受的答案!

1
为我工作,只需注意'start'是'block'参数的默认值。
Liron Lavi

@Ben Carp的答案不起作用时,这对我有用。
Jason Masters

37

只需找到您已经确定的元素的最高位置https://www.w3schools.com/Jsref/prop_element_offsettop.asp,然后通过scrollTo方法https://www.w3schools.com/Jsref/met_win_scrollto.asp滚动到该位置

这样的事情应该起作用:

handleScrollToElement(event) {
  const tesNode = ReactDOM.findDOMNode(this.refs.test)
  if (some_logic){
    window.scrollTo(0, tesNode.offsetTop);
  }
}

render() {

  return (
    <div>
      <div ref="test"></div>
    </div>)
}

更新:

因为阵营v16.3React.createRef()优选

constructor(props) {
  super(props);
  this.myRef = React.createRef();
}

handleScrollToElement(event) {
  if (<some_logic>){
    window.scrollTo(0, this.myRef.current.offsetTop);
  }
}

render() {

  return (
    <div>
      <div ref={this.myRef}></div>
    </div>)
}

2
这是更好的答案。使用ReactDOM.findDomNode()是更好的做法-由于React会重新渲染组件,因此您在调用该函数时可能根本不存在仅通过其ID获得的div
好主意

4
根据官方文档,您应尽量避免使用findDOMNode。在大多数情况下,您可以将ref附加到DOM节点,而完全避免使用findDOMNode
Facyo Kouch

1
注意,使用this.refs通过串映射已被弃用,请参阅:stackoverflow.com/questions/43873511/...
Himmet Avsar

1
注意:我必须使用this.myRef.current.scrollIntoView()而不是window.scrollTo(0, this.myRef)
Babbz77 '18 -10-24

14

最终将不建议使用findDOMNode。

首选方法是使用回调引用。

github eslint


3
请包括链接材料的相关部分,以防万一被删除,您的答案不会变得毫无用处。
totymedli

12

您现在可以使用useRef来自React Hook API

https://reactjs.org/docs/hooks-reference.html#useref

宣言

let myRef = useRef()

零件

<div ref={myRef}>My Component</div>

window.scrollTo({ behavior: 'smooth', top: myRef.current.offsetTop })

我正在尝试使用您的代码。我可以看到,console.log它正在执行您的window.scrollTo语句(针对我的情况进行了调整),但是它不会滚动。这可能与我正在使用React Bootstrap Modal有关吗?
robertwerner_sf

9

您还可以使用scrollIntoView方法滚动到给定的元素。

handleScrollToElement(event) {
const tesNode = ReactDOM.findDOMNode(this.refs.test)
 if (some_logic){
  tesNode.scrollIntoView();
  }
 }

 render() {
  return (
   <div>
     <div ref="test"></div>
   </div>)
}

9

我可能参加聚会的时间很晚,但是我试图以适当的方式对项目实施动态引用,并且找到所有答案,直到知道并不能完全满足我的喜好,所以我想出了一个我认为是的解决方案简单,并使用本机和推荐的反应方式来创建引用。

有时,您会发现文档的编写方式假定您拥有已知的视图数量,并且在大多数情况下该数量是未知的,因此在这种情况下,您需要一种解决问题的方法,对所需数量的未知视图创建动态引用在课堂上展示

因此,我能想到并能完美工作的最简单的解决方案是执行以下操作

class YourClass extends component {

state={
 foo:"bar",
 dynamicViews:[],
 myData:[] //get some data from the web
}

inputRef = React.createRef()

componentDidMount(){
  this.createViews()
}


createViews = ()=>{
const trs=[]
for (let i = 1; i < this.state.myData.lenght; i++) {

let ref =`myrefRow ${i}`

this[ref]= React.createRef()

  const row = (
  <tr ref={this[ref]}>
<td>
  `myRow ${i}`
</td>
</tr>
)
trs.push(row)

}
this.setState({dynamicViews:trs})
}

clickHandler = ()=>{

//const scrollToView = this.inputRef.current.value
//That to select the value of the inputbox bt for demostrate the //example

value=`myrefRow ${30}`

  this[value].current.scrollIntoView({ behavior: "smooth", block: "start" });
}


render(){

return(
<div style={{display:"flex", flexDirection:"column"}}>
<Button onClick={this.clickHandler}> Search</Button>
<input ref={this.inputRef}/>
<table>
<tbody>
{this.state.dynamicViews}
<tbody>
<table>
</div>


)

}

}

export default YourClass

这样,滚动条将转到您要查找的任何行。

欢呼,希望对别人有帮助


8

2019年7月-专用挂钩/功能

专用的挂钩/函数可以隐藏实现细节,并为您的组件提供简单的API。

React 16.8 +功能组件

const useScroll = () => {
  const htmlElRef = useRef(null)
  const executeScroll = () => window.scrollTo(0, htmlElRef.current.offsetTop)

  return [executeScroll, htmlElRef]
}

在任何功能组件中使用它。

const ScrollDemo = () => {
    const [executeScroll, htmlElRef] = useScroll()
    useEffect(executeScroll, []) // Runs after component mounts

    return <div ref={htmlElRef}>Show me</div> 
}

完整演示

React 16.3 +类组件

const utilizeScroll = () => {
  const htmlElRef = React.createRef()
  const executeScroll = () => window.scrollTo(0, htmlElRef.current.offsetTop)

  return {executeScroll, htmlElRef}
}

在任何类组件中使用它。

class ScrollDemo extends Component {
  constructor(){
    this.elScroll = utilizeScroll()
  }

  componentDidMount(){
    this.elScroll.executeScroll()
  }

  render(){
    return <div ref={this.elScroll.htmlElRef}>Show me</div> 
  }
} 

完整演示


7

您可以这样尝试:

 handleScrollToElement = e => {
    const elementTop = this.gate.offsetTop;
    window.scrollTo(0, elementTop);
 };

 render(){
  return(
      <h2 ref={elem => (this.gate = elem)}>Payment gate</h2>
 )}

好的解决方案,尽管您可能想要e.offsetTop而不是this.gate.offsetTop,然后将this.gate传递给函数。
虚伪的国王

5

您可以使用类似 componentDidUpdate

componentDidUpdate() {
  var elem = testNode //your ref to the element say testNode in your case; 
  elem.scrollTop = elem.scrollHeight;
};

3
我认为在反应中不优选使用元素ID。它打破了虚拟的dom概念
-iamsaksham

使用生命周期方法是运行WHEN / WHERE的最佳方式。但可能想使用此答案中看到的其他方法作为实际代码
Dameo

3

我有一个简单的场景,当用户单击我的Material UI导航栏中的菜单项时,我想将它们向下滚动到页面上的该部分。我可以使用ref并将它们穿入所有组件,但是我讨厌threading props支持多个组件,因为这会使代码易碎。

我只是在我的react组件中使用了Vanilla JS,事实证明它可以正常工作。在要滚动到的元素上放置一个ID,然后在标头组件中执行此操作。

const scroll = () => {
  const section = document.querySelector( '#contact-us' );
  section.scrollIntoView( { behavior: 'smooth', block: 'start' } );
};

2

跟着这些步骤:

1)安装:

npm install react-scroll-to --save

2)导入包:

import { ScrollTo } from "react-scroll-to";

3)用法:

class doc extends Component {
  render() {
    return(
      <ScrollTo>
        {({ scroll }) => (
          <a onClick={() => scroll({ x: 20, y: 500, , smooth: true })}>Scroll to Bottom</a>
        )}
      </ScrollTo>
    )
  }
}

2

这是您可以用来解决此问题的类组件代码片段:

该方法使用了参考,并且还可以平滑滚动到目标参考

import React, { Component } from 'react'

export default class Untitled extends Component {
  constructor(props) {
    super(props)
    this.howItWorks = React.createRef() 
  }

  scrollTohowItWorks = () =>  window.scroll({
    top: this.howItWorks.current.offsetTop,
    left: 0,
    behavior: 'smooth'
  });

  render() {
    return (
      <div>
       <button onClick={() => this.scrollTohowItWorks()}>How it works</button>
       <hr/>
       <div className="content" ref={this.howItWorks}>
         Lorem ipsum dolor, sit amet consectetur adipisicing elit. Nesciunt placeat magnam accusantium aliquid tenetur aspernatur nobis molestias quam. Magnam libero expedita aspernatur commodi quam provident obcaecati ratione asperiores, exercitationem voluptatum!
       </div>
      </div>
    )
  }
}

1

对我有用的是:

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.myRef = React.createRef(); // Create a ref    
    }

    // Scroll to ref function
    scrollToMyRef = () => {
        window.scrollTo({
            top:this.myRef.offsetTop, 
            // behavior: "smooth" // optional
        });
    };

    // On component mount, scroll to ref
    componentDidMount() {
        this.scrollToMyRef();
    }

    // Render method. Note, that `div` element got `ref`.
    render() {
        return (
            <div ref={this.myRef}>My component</div>
        )
    }
}

1

请注意,我无法将这些解决方案用于Material UI组件。看起来他们没有current物业。

我只是div在我的组件之间添加了一个空白,并在其上设置了ref属性。


0
 <div onScrollCapture={() => this._onScrollEvent()}></div>

 _onScrollEvent = (e)=>{
     const top = e.nativeEvent.target.scrollTop;
     console.log(top); 
}


0

我在onclick函数中使用了此函数,以平滑地滚动到其ID为“ step2Div”的div。

let offset = 100;
window.scrollTo({
    behavior: "smooth",
    top:
    document.getElementById("step2Div").getBoundingClientRect().top -
    document.body.getBoundingClientRect().top -
    offset
});

0

最好的方法是使用element.scrollIntoView({ behavior: 'smooth' })。这样可以将元素滚动到带有漂亮动画的视图中。

当将其与React结合使用时useRef(),可以通过以下方式完成。

import React, { useRef } from 'react'

const Article = () => {
  const titleRef = useRef()

  function handleBackClick() {
      titleRef.current.scrollIntoView({ behavior: 'smooth' })
  }

  return (
      <article>
            <h1 ref={titleRef}>
                A React article for Latin readers
            </h1>

            // Rest of the article's content...

            <button onClick={handleBackClick}>
                Back to the top
            </button>
        </article>
    )
}

当您想滚动到React组件时,需要将ref转发到渲染的元素。本文将深入探讨该问题

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.