ReactJS如何滚动到一个元素

edm*_*rto 112 javascript ecmascript-6 reactjs

我有一个聊天小部件,每次我向上滚动时都会提取一系列消息.我现在面临的问题是,当消息加载时,滑块保持固定在顶部,我希望它专注于前一个数组的最后一个索引元素.我发现我可以通过传递索引来制作动态引用,但我还需要知道使用什么样的滚动函数来实现

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

  render() {

    return (
      <div>
        <div ref="test"></div>
      </div>)
  }
Run Code Online (Sandbox Code Playgroud)

Ben*_*arp 160

选项1:使用React.createRef(React 16.3 +)

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> 
      </>
   )
}

Run Code Online (Sandbox Code Playgroud)

选项2:使用ref回调

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. 

}
Run Code Online (Sandbox Code Playgroud)

不要使用String refs.

字符串引用了伤害性能,不可组合,并且在那里(2018年8月).

字符串引用有一些问题,被认为是遗留问题,很可能会在未来的某个版本中删除.[官方反应文件]

resource1,resource2


原则

  1. ref只能存储在类组件中.(这将在将来发布ref hook时发生变化)
  2. 为了滚动到一个元素,类中的ref属性必须附加到一个实际的dom元素; 我们使用浏览器的本机滚动方法,我们需要知道元素在页面上的实际位置.
  3. ref(在上面提出的任何一种方法中)都可以作为道具传递给孩子.

将ref传给孩子

React.createRef -将ref对象作为prop传递给子组件.

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. 
}
Run Code Online (Sandbox Code Playgroud)

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

/* css */
html {
    scroll-behavior: smooth;
}
Run Code Online (Sandbox Code Playgroud)

更新

在过去,我建议将选项对象传递给__CODE__.EdgeiOS尚不支持此表单.

  • `window.scrollTo(0,offsetTop)`是一个更好的选择,在当前浏览器中有更好的支持 (3认同)
  • 事后很明显,但重要的是要提到这只适用于原生DOM元素,而不仅仅适用于任何React组件. (3认同)
  • @SimonFranzen看看我更新的答案 - TLDR - 类组件案例.当调用scrollToMyRef时,它将滚动到你附加引用的子节点.您可以将该方法传递给其他子组件,并从那里触发它. (2认同)

Rom*_*mov 35

只需找到您已确定的元素的顶部位置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>)
}
Run Code Online (Sandbox Code Playgroud)

更新:

因为阵营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>)
}
Run Code Online (Sandbox Code Playgroud)

  • 根据官方文档,您应该尽量避免使用`findDOMNode`.在大多数情况下,您可以将引用附加到DOM节点,并避免使用`findDOMNode`. (3认同)
  • 这是更好的答案。使用 `ReactDOM.findDomNode()` 是更好的实践 - 因为 React 重新渲染组件,所以当你调用函数时,你只是通过其 ID 获得的 div 可能不存在 (2认同)

chi*_*hii 24

这对我有用

this.anyRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' })
Run Code Online (Sandbox Code Playgroud)

  • 把这个放在哪里 (2认同)
  • 奇迹般有效。以上都不适合我,这应该被接受的答案! (2认同)

sww*_*314 14

使用findDOMNode最终将被弃用.

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

github eslint

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

Ben*_*arp 13

2019 年 7 月 - 专用钩子/函数

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

React 16.8 + 函数式组件

const useScroll = () => {
  const elRef = useRef(null);
  const executeScroll = () => elRef.current.scrollIntoView();

  return [executeScroll, elRef];
};
Run Code Online (Sandbox Code Playgroud)

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

const ScrollDemo = () => {
    const [executeScroll, elRef] = useScroll()
    useEffect(executeScroll, []) // Runs after component mounts
    
    return <div ref={elRef}>Element to scroll to</div> 
}
Run Code Online (Sandbox Code Playgroud)

完整演示

React 16.3 + 类组件

const ScrollDemo = () => {
    const [executeScroll, elRef] = useScroll()
    useEffect(executeScroll, []) // Runs after component mounts
    
    return <div ref={elRef}>Element to scroll to</div> 
}
Run Code Online (Sandbox Code Playgroud)

在任何类组件中使用它。

const utilizeScroll = () => {
  const elRef = React.createRef();
  const executeScroll = () => elRef.current.scrollIntoView();

  return { executeScroll, elRef };
};
Run Code Online (Sandbox Code Playgroud)

完整演示


Jos*_*ose 10

我有一个简单的场景,当用户单击我的 Material UI 导航栏中的菜单项时,我想将它们向下滚动到页面上的部分。我可以使用 refs 并将它们穿过所有组件,但我讨厌线程 props props 多个组件,因为这会使代码变得脆弱。

我只是在我的 React 组件中使用了 vanilla JS,结果它工作得很好。在我想要滚动到的元素上放置了一个 ID,在我的标题组件中我只是这样做了。

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

  • 是的,这在技术上是一种反模式,首选方法是使用 refs。但是,如果您的组件与组件树中的另一个组件不接近,那么线程引用将是一场噩梦。我做出了一个权衡决定,在这种情况下,由于使用 ref 带来的技术复杂性,不使用 refs 是可以的。 (2认同)

rob*_*ten 10

最好的方法是使用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>
    )
}
Run Code Online (Sandbox Code Playgroud)

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


小智 9

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

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

 render() {
  return (
   <div>
     <div ref="test"></div>
   </div>)
}
Run Code Online (Sandbox Code Playgroud)


小智 9

这个解决方案在 ReactJS 中适用于我

在 header.js 中

function scrollToTestDiv(){
      const divElement = document.getElementById('test');
      divElement.scrollIntoView({ behavior: 'smooth' });
    }

<a class="nav-link" onClick={scrollToTestDiv}> Click here! </a>
Run Code Online (Sandbox Code Playgroud)

在index.html中

<div id="test"></div>
Run Code Online (Sandbox Code Playgroud)


Rob*_*ole 9

<div id="componentToScrollTo"><div>

<a href='#componentToScrollTo'>click me to scroll to this</a>
Run Code Online (Sandbox Code Playgroud)


小智 8

我可能会迟到了,但我试图实现动态裁判给我的项目的正确方法,我发现,直到知道是不是安静满意我喜欢所有的答案,所以我想到了,我认为是一个解决方案简单并使用原生和推荐的反应方式来创建引用.

有时你会发现该文件被写的方式假定您有意见已知量,在大多数情况下,所以你需要一种方法来解决这个问题,在这种情况下,创建动态裁判未知若干意见你需要这个数是未知在课堂上展示

因此,我能想到并且完美无缺的最简单的解决方案就是如下所示

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
Run Code Online (Sandbox Code Playgroud)

这样滚动将转到您正在寻找的任何行..

欢呼,希望它能帮助别人


jir*_*ova 7

你可以这样试试:

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

 render(){
  return(
      <h2 ref={elem => (this.gate = elem)}>Payment gate</h2>
 )}
Run Code Online (Sandbox Code Playgroud)


Tan*_*han 6

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

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

宣言

let myRef = useRef()
Run Code Online (Sandbox Code Playgroud)

零件

<div ref={myRef}>My Component</div>
Run Code Online (Sandbox Code Playgroud)

使用

window.scrollTo({ behavior: 'smooth', top: myRef.current.offsetTop })
Run Code Online (Sandbox Code Playgroud)


T.M*_*T.M 6

如何在页面渲染期间滚动到Reactjs中的某些元素

import React, { useEffect, useRef } from 'react'

const YourComponent = () => {
  const yourElementRef = useRef(null);

  useEffect(() => {
    if (yourElementRef.current) {
      yourElementRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, []);

  return (
    <div ref={yourElementRef}>Element to scroll to</div>
  );
}
Run Code Online (Sandbox Code Playgroud)

当状态改变时如何滚动到Reactjs中的某个元素

import React, { useEffect, useRef, useState } from 'react'

const YourComponent = () => {
  const [stateValue, setStateValue] = useState()
  const yourElementRef = useRef(null);

  useEffect(() => {
    if (yourElementRef.current) {
      yourElementRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, [stateValue]);

  return (
    <div ref={yourElementRef}>Element to scroll to</div>
  );
}
Run Code Online (Sandbox Code Playgroud)


Rav*_*eja 5

你可以使用类似的东西 componentDidUpdate

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

  • 我认为使用元素id在反应中不是首选.它打破了虚拟的dom概念 (3认同)

bel*_*ola 5

以下是可用于解决此问题的类组件代码片段:

这种方法使用了 ref 并且还平滑地滚动到目标 ref

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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)


Fab*_*ert 5

如果有人使用 Typescript,这里是 Ben Carp 的答案:

import { RefObject, useRef } from 'react';

export const useScroll = <T extends HTMLElement>(
  options?: boolean | ScrollIntoViewOptions
): [() => void, RefObject<T>] => {
  const elRef = useRef<T>(null);
  const executeScroll = (): void => {
    if (elRef.current) {
      elRef.current.scrollIntoView(options);
    }
  };

  return [executeScroll, elRef];
};
Run Code Online (Sandbox Code Playgroud)


DIN*_*LIT 5

您可以useRef与 一起使用scrollIntoView

  • 用于useRef要滚动到的元素:这里我想滚动到 PieceTabs 元素,这就是为什么我用 Box(div) 包裹它,这样我就可以访问 dom 元素

您可能熟悉 refs 主要是作为访问 DOM 的一种方式。如果你使用 ref 对象传递给 React,只要该节点发生变化,React 就会将其 .current 属性设置为相应的 DOM 节点。请参阅文档

...
const tabsRef = useRef()
...
<Box ref={tabsRef}>
   <PieceTabs piece={piece} value={value} handleChange={handleChange} />
</Box>
...
Run Code Online (Sandbox Code Playgroud)
  • 创建一个处理此滚动的函数:
  const handleSeeCompleteList = () => {
    const tabs = tabsRef.current
    if (tabs) {
      tabs.scrollIntoView({
        behavior: 'smooth',
        block: 'start',
      })
    }
  }
Run Code Online (Sandbox Code Playgroud)
  • 单击滚动到目标后,在所需的元素上调用此函数:
 <Typography
  variant="body2"
  sx={{
    color: "#007BFF",
    cursor: "pointer",
    fontWeight: 500,
  }}
  onClick={(e) => {
    handleChange(e, 2);
    handleSeeCompleteList(); // here we go
  }}
>
  Voir toute la liste
</Typography>;
Run Code Online (Sandbox Code Playgroud)

现在我们开始 React Js滚动到使用useRef和scrollIntoView