Wie scrolle ich zu einem Element?

180

Ich habe ein Chat-Widget, das bei jedem Bildlauf eine Reihe von Nachrichten abruft. Das Problem, mit dem ich jetzt konfrontiert bin, ist, dass der Schieberegler beim Laden von Nachrichten oben fixiert bleibt. Ich möchte, dass es sich auf das letzte Indexelement aus dem vorherigen Array konzentriert. Ich habe herausgefunden, dass ich dynamische Refs erstellen kann, indem ich den Index übergebe, aber ich müsste auch wissen, welche Art von Bildlauffunktion ich verwenden muss, um dies zu erreichen

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

  render() {

    return (
      <div>
        <div ref="test"></div>
      </div>)
  }
edmamerto
quelle
1
Für eine gebündelte Lösung: npmjs.com/package/react-scroll-to-component
tokland

Antworten:

301

Reaktion 16.8 +, Funktionskomponente

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

Klicken Sie hier für eine vollständige Demo zu StackBlits

Reagiere 16.3 +, Klassenkomponente

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. 

}

Klassenkomponente - Ref-Rückruf

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. 
}

Verwenden Sie keine String-Refs.

String-Refs beeinträchtigen die Leistung, sind nicht zusammensetzbar und befinden sich auf dem Weg nach draußen (August 2018).

String-Refs haben einige Probleme, gelten als Legacy und werden wahrscheinlich in einer der zukünftigen Versionen entfernt. [Offizielle Reaktionsdokumentation]

resource1 resource2

Optional: Glätten Sie die Scroll-Animation

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

Ref an ein Kind weitergeben

Wir möchten, dass der ref an ein dom-Element angehängt wird, nicht an eine Reaktionskomponente. Wenn wir es also an eine untergeordnete Komponente übergeben, können wir die Requisitenreferenz nicht benennen.

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

Befestigen Sie dann die Ref-Stütze an einem Dom-Element.

const ChildComp = (props) => {
    return <div ref={props.refProp} />
}
Ben Carp
quelle
5
window.scrollTo(0, offsetTop)ist eine bessere Option mit besserer Unterstützung unter den aktuellen Browsern
MoMo
1
Könnte sicherstellen, dass Sie in Ihrem Beispiel konsistent sind. Wir beginnen mit myRef, gehen mit domRef und enden mit tesNode ?. Das ist ziemlich verwirrend
Louis Lecocq
4
Im Nachhinein offensichtlich, aber es ist wichtig zu erwähnen, dass dies nur für native DOM-Elemente und nicht für jede React-Komponente funktioniert.
jpunk11
1
@ jpunk11 Ich habe gerade meine Antwort aktualisiert. In der aktualisierten Antwort wird erläutert, wie Sie zu einem dom-Element scrollen, das sich in einer untergeordneten Klassenkomponente befindet.
Ben Carp
2
@SimonFranzen Schauen Sie sich meine aktualisierte Antwort an - TLDR - Klassenkomponentenfall. Wenn scrollToMyRef aufgerufen wird, wird zu dem Kind gescrollt, an das Sie den Verweis angehängt haben. Sie können die Methode an eine andere untergeordnete Komponente übergeben und von dort aus auslösen.
Ben Carp
54

das hat bei mir funktioniert

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

EDIT: Ich wollte dies basierend auf den Kommentaren erweitern.

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

<div ref={scrollTo}>Item</div>
chii
quelle
1
wo dies zu setzen
su_sundariya
in Lebenszyklusmethode oder Konstruktor
su_sundariya
1
Klappt wunderbar. Keines der oben genannten funktioniert bei mir nicht, dies sollte als Antwort akzeptiert werden!
Shin
1
Beachten Sie, dass 'start' der Standardwert des Parameters 'block' ist.
Liron Lavi
Dies funktionierte für mich, als die Antwort von @Ben Carp nicht stimmte.
Jason Masters
37

Suchen Sie einfach die oberste Position des Elements, das Sie bereits bestimmt haben: https://www.w3schools.com/Jsref/prop_element_offsettop.asp, und scrollen Sie dann über die scrollToMethode https://www.w3schools.com/Jsref/met_win_scrollto.asp zu dieser Position

So etwas sollte funktionieren:

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

AKTUALISIEREN:

da Reagieren v16.3 die React.createRef()bevorzugt

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>)
}
Roman Maksimov
quelle
2
Dies ist die bessere Antwort. Verwenden ReactDOM.findDomNode()ist eine bessere Vorgehensweise - da React Komponenten neu rendert, ist ein Div, das Sie einfach anhand seiner ID erhalten, möglicherweise nicht vorhanden, wenn Sie die Funktion aufrufen
Good Idea
4
Gemäß der offiziellen Dokumentation sollten Sie versuchen, die Verwendung zu vermeiden findDOMNode. In den meisten Fällen können Sie dem DOM-Knoten eine Referenz hinzufügen und die Verwendung findDOMNodeüberhaupt vermeiden .
Facyo Kouch
1
Beachten Sie, dass die Verwendung von this.refs durch Zeichenfolgenzuordnung veraltet ist, siehe: stackoverflow.com/questions/43873511/…
Himmet Avsar
1
Hinweis: Ich musste this.myRef.current.scrollIntoView()statt verwenden window.scrollTo(0, this.myRef).
Babbz77
14

Die Verwendung von findDOMNode wird irgendwann veraltet sein.

Die bevorzugte Methode ist die Verwendung von Rückrufreferenzen.

Github Eslint

sww314
quelle
3
Bitte fügen Sie den relevanten Teil des verlinkten Materials hinzu, damit Ihre Antwort nicht unbrauchbar wird, falls sie entfernt wird.
Totymedli
12

Sie können jetzt die useRefReact Hook-API verwenden

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

Erklärung

let myRef = useRef()

Komponente

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

Verwenden

window.scrollTo({ behavior: 'smooth', top: myRef.current.offsetTop })
Tanapruk Tangphianphan
quelle
Ich versuche Ihren Code zu verwenden. Ich kann sehen, console.logdass es Ihre window.scrollToAnweisung ausführt (angepasst für meinen Fall), aber dennoch nicht scrollt. Könnte dies mit der Tatsache zusammenhängen, dass ich ein React Bootstrap Modal verwende?
robertwerner_sf
9

Sie können auch eine scrollIntoViewMethode verwenden, um zu einem bestimmten Element zu scrollen.

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

 render() {
  return (
   <div>
     <div ref="test"></div>
   </div>)
}
Farshad J.
quelle
9

Ich bin vielleicht zu spät zur Party gekommen, aber ich habe versucht, dynamische Refs auf die richtige Weise in mein Projekt zu implementieren, und alle Antworten, die ich bis dahin gefunden habe, sind nicht ganz zufriedenstellend für meinen Geschmack. Deshalb habe ich eine Lösung gefunden, die ich für richtig halte einfach und verwendet die native und empfohlene Reaktionsweise, um die Referenz zu erstellen.

Manchmal stellen Sie fest, dass die Art und Weise, wie die Dokumentation geschrieben wird, davon ausgeht, dass Sie über eine bekannte Anzahl von Ansichten verfügen. In den meisten Fällen ist diese Anzahl unbekannt. In diesem Fall benötigen Sie eine Möglichkeit, das Problem zu lösen. Erstellen Sie dynamische Verweise auf die unbekannte Anzahl von Ansichten, die Sie benötigen in der Klasse zu zeigen

Die einfachste Lösung, die ich mir vorstellen konnte und die einwandfrei funktionierte, war Folgendes

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

Auf diese Weise wechselt die Schriftrolle zu der gewünschten Zeile.

Prost und hoffe, es hilft anderen

Miguel Sedek
quelle
8

Jul 2019 - Dedizierter Haken / Funktion

Ein dedizierter Hook / eine dedizierte Funktion kann Implementierungsdetails verbergen und bietet Ihren Komponenten eine einfache API.

Reagiere 16.8 + Funktionskomponente

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

  return [executeScroll, htmlElRef]
}

Verwenden Sie es in jeder Funktionskomponente.

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

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

vollständige Demo

Reagiere 16.3 + Klassenkomponente

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

  return {executeScroll, htmlElRef}
}

Verwenden Sie es in einer beliebigen Klassenkomponente.

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

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

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

Vollständige Demo

Ben Carp
quelle
7

Sie könnten es so versuchen:

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

 render(){
  return(
      <h2 ref={elem => (this.gate = elem)}>Payment gate</h2>
 )}
Jirina Brezinova
quelle
Gute Lösung, obwohl Sie wahrscheinlich eher e.offsetTop als this.gate.offsetTop möchten und dieses.gate dann an die Funktion übergeben möchten.
KingOfHypocrites
5

Sie können so etwas wie verwenden componentDidUpdate

componentDidUpdate() {
  var elem = testNode //your ref to the element say testNode in your case; 
  elem.scrollTop = elem.scrollHeight;
};
Raviteja
quelle
3
Ich denke, die Verwendung der Element-ID wird bei der Reaktion nicht bevorzugt. Es bricht das virtuelle Dom-Konzept
iamsaksham
Die Verwendung der Lebenszyklusmethode ist der Weg bis zu WHEN / WHERE, um den Code auszuführen. Aber wahrscheinlich möchten Sie die anderen Methoden verwenden, die Sie in dieser Antwort für den tatsächlichen Code sehen
Dameo
3

Ich hatte ein einfaches Szenario: Wenn der Benutzer auf den Menüpunkt in meiner Navigationsleiste für die Material-Benutzeroberfläche klickt, möchte ich ihn zu dem Abschnitt auf der Seite scrollen. Ich könnte Refs verwenden und sie durch alle Komponenten fädeln, aber ich hasse es, Requisiten mit mehreren Komponenten zu fädeln, weil dies den Code zerbrechlich macht.

Ich habe gerade Vanilla JS in meiner Reaktionskomponente verwendet, es stellt sich heraus, dass es gut funktioniert. Platzierte eine ID auf dem Element, zu dem ich scrollen wollte, und in meiner Header-Komponente habe ich dies einfach getan.

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

Folge diesen Schritten:

1) Installieren:

npm install react-scroll-to --save

2) Importieren Sie das Paket:

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

3) Verwendung:

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

Hier ist das Code-Snippet für Klassenkomponenten, mit dem Sie dieses Problem lösen können:

Dieser Ansatz verwendet die Referenz und scrollt auch reibungslos zur Zielreferenz

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>
    )
  }
}
Bello Hargbola
quelle
1

Was hat bei mir funktioniert:

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>
        )
    }
}
Artur Barseghyan
quelle
1

Nur ein Kopf hoch, ich konnte diese Lösungen nicht dazu bringen, an Material UI-Komponenten zu arbeiten. Sieht so aus, als hätten sie das nichtcurrent Grundstück nicht.

Ich habe gerade ein Leerzeichen divunter meinen Komponenten hinzugefügt und die Ref-Requisite darauf gesetzt.

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

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

Ich habe dies in einer Onclick-Funktion verwendet, um reibungslos zu einem Div zu scrollen, dessen ID "step2Div" ist.

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

Der schönste Weg ist zu benutzen element.scrollIntoView({ behavior: 'smooth' }). Dadurch wird das Element mit einer schönen Animation angezeigt.

Wenn Sie es mit React's kombinieren useRef(), können Sie wie folgt vorgehen.

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

Wenn Sie zu einer React-Komponente scrollen möchten, müssen Sie den Verweis an das gerenderte Element weiterleiten. Dieser Artikel wird tiefer in das Problem eintauchen .

robinvdvleuten
quelle