Come scorrere fino a un elemento?


181

Ho un widget di chat che visualizza una serie di messaggi ogni volta che scorro verso l'alto. Il problema che sto affrontando ora è che il dispositivo di scorrimento rimane fisso in alto quando i messaggi vengono caricati. Voglio che si concentri sull'ultimo elemento indice dell'array precedente. Ho capito che posso fare riferimenti dinamici passando l'indice, ma avrei anche bisogno di sapere quale tipo di funzione di scorrimento usare per raggiungere questo

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

  render() {

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

1
Per una soluzione in bundle: npmjs.com/package/react-scroll-to-component
tokland

Risposte:


303

Reagire 16.8+, Componente funzionale

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

Fai clic qui per una demo completa su StackBlits

Reagire 16.3 +, componente di classe

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. 

}

Componente di classe - Richiamata di riferimento

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

Non usare i riferimenti di stringa.

I riferimenti alle stringhe danneggiano le prestazioni, non sono compostabili e stanno per uscire (agosto 2018).

i riferimenti alle stringhe presentano alcuni problemi, sono considerati legacy e possono essere rimossi in una delle versioni future. [Documentazione ufficiale di React]

risorsa1 risorsa2

Opzionale: Animazione scorrimento Smoothe

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

Passando ref a un bambino

Vogliamo che l'arbitro sia collegato a un elemento dom, non a un componente di reazione. Quindi quando lo si passa a un componente figlio non possiamo nominare il riferimento prop.

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

Quindi collegare l'elica di riferimento a un elemento dom.

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

5
window.scrollTo(0, offsetTop)è un'opzione migliore con un migliore supporto tra i browser attuali
MoMo,

1
Potrebbe assicurarti di essere coerente nel tuo esempio. Stiamo iniziando da myRef, andando con domRef e finendo con tesNode?. È abbastanza confuso
Louis Lecocq,

4
Ovvio dopo il fatto, ma è importante menzionare che questo funziona solo per elementi DOM nativi e non solo per qualsiasi componente React.
jpunk11,

1
@ jpunk11 Ho appena aggiornato la mia risposta. La risposta aggiornata spiega come scorrere fino a un elemento dom che si trova in un componente di classe figlio.
Ben Carp,

2
@SimonFranzen Dai un'occhiata alla mia risposta aggiornata, il caso del componente di classe TLDR. Quando si chiama scrollToMyRef, scorrerà fino al bambino a cui è stato collegato il riferimento. È possibile passare il metodo a un componente figlio diverso e attivarlo da lì.
Ben Carp,

55

questo ha funzionato per me

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

EDIT: volevo espandere questo in base ai commenti.

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

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

1
dove metterlo
su_sundariya il

nel metodo del ciclo di vita o costruttore
su_sundariya

1
Funziona come un fascino. Nessuna delle precedenti non funziona per me, questa dovrebbe essere una risposta accettata!
Shin,

1
Ha funzionato per me, basta notare che 'start' è il valore predefinito del parametro 'block'.
Liron Lavi

Questo ha funzionato per me quando la risposta di @Ben Carp no.
Jason Masters

37

Basta trovare la prima posizione dell'elemento che hai già determinato https://www.w3schools.com/Jsref/prop_element_offsettop.asp quindi scorrere fino a questa posizione tramite il scrollTometodo https://www.w3schools.com/Jsref/met_win_scrollto.asp

Qualcosa del genere dovrebbe funzionare:

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

AGGIORNARE:

poiché React v16.3 la React.createRef()è preferito

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
Questa è la risposta migliore L'uso ReactDOM.findDomNode()è una pratica migliore - poiché React esegue il rendering di nuovo i componenti, un div che ottieni semplicemente dal suo ID potrebbe non esistere quando chiami la funzione
Buona idea

4
Secondo la documentazione ufficiale, dovresti cercare di evitare l'uso findDOMNode. Nella maggior parte dei casi, è possibile collegare un riferimento al nodo DOM ed evitare di utilizzarlo findDOMNodeaffatto.
Facyo Kouch,

1
Si noti che utilizzano this.refs di mappatura stringa è deprecato, vedi: stackoverflow.com/questions/43873511/...
Himmet Avsar

1
Nota: ho dovuto usare al this.myRef.current.scrollIntoView()posto di window.scrollTo(0, this.myRef).
Babbz77,

14

L'uso di findDOMNode alla fine sarà deprecato.

Il metodo preferito è utilizzare i riferimenti di callback.

github eslint


3
Includi la parte pertinente del materiale collegato in modo che, nel caso in cui venga rimosso, la tua risposta non diventi inutile.
totymedli,

12

Ora puoi usare useRef dall'API di reazione hook

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

dichiarazione

let myRef = useRef()

componente

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

Uso

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

Sto cercando di usare il tuo codice. Vedo console.logche sta eseguendo la tua window.scrollTodichiarazione (adattata al mio caso) ma non scorre. Questo potrebbe essere correlato al fatto che sto usando un Reast Bootstrap Modal?
robertwerner_sf,

9

Puoi anche usare il scrollIntoViewmetodo per scorrere fino a un dato elemento.

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

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

9

Potrei essere in ritardo alla festa, ma stavo cercando di implementare ref dinamici per il mio progetto nel modo giusto e tutte le risposte che ho trovato fino a quando non so che non sono abbastanza soddisfacenti per i miei gusti, quindi ho trovato una soluzione che penso sia semplice e utilizza il modo nativo e raccomandato di reazione per creare il rif.

a volte ti accorgi che il modo in cui viene scritta la documentazione presuppone che tu abbia un numero noto di visualizzazioni e nella maggior parte dei casi questo numero è sconosciuto, quindi in questo caso hai bisogno di un modo per risolvere il problema, crea riferimenti dinamici al numero sconosciuto di visualizzazioni necessarie per mostrare in classe

quindi la soluzione più semplice che mi è venuta in mente e che ho funzionato alla perfezione è stata la seguente

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

in questo modo la pergamena andrà a qualunque riga tu stia cercando ..

applausi e spero che aiuti gli altri


8

Luglio 2019 - Gancio / funzione dedicati

Un hook / funzione dedicato può nascondere i dettagli di implementazione e fornisce una semplice API ai tuoi componenti.

Reagire 16.8 + Componente funzionale

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

  return [executeScroll, htmlElRef]
}

Usalo in qualsiasi componente funzionale.

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

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

demo completa

Reagire 16.3 + componente di classe

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

  return {executeScroll, htmlElRef}
}

Usalo in qualsiasi componente di classe.

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

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

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

Demo completa


7

Puoi provare in questo modo:

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

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

Buona soluzione, anche se probabilmente si desidera e.offsetTop anziché this.gate.offsetTop e quindi passare questo.gate alla funzione.
KingOf Hypocrites,

5

Puoi usare qualcosa di simile componentDidUpdate

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

3
penso che usare ID elemento non sia preferito in reagire. Si rompe il concetto di dom virtuale
iamsaksham

L'uso del metodo del ciclo di vita è la strada da percorrere per QUANDO / DOVE eseguire il codice. Ma probabilmente vuoi usare le altre metodologie che vedi in questa risposta per il codice attuale
Dameo,

3

Ho avuto uno scenario semplice, quando l'utente fa clic sulla voce di menu nella mia barra dei materiali dell'interfaccia utente, voglio scorrere fino alla sezione della pagina. Potrei usare i ref e inserirli in tutti i componenti, ma odio il thread di oggetti di scena che propongono più componenti perché ciò rende il codice fragile.

Ho appena usato la vaniglia JS nel mio componente di reazione, a quanto pare funziona perfettamente. Posizionato un ID sull'elemento che volevo scorrere e nel mio componente di intestazione ho appena fatto questo.

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

2

Segui questi passi:

1) Installa:

npm install react-scroll-to --save

2) Importa il pacchetto:

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

3) Utilizzo:

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

2

Ecco lo snippet di codice del componente di classe che è possibile utilizzare per risolvere questo problema:

Questo approccio utilizzava il riferimento e scorre anche senza problemi fino al riferimento target

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

2

Il modo migliore è usare element.scrollIntoView({ behavior: 'smooth' }). Questo fa scorrere l'elemento in vista con una bella animazione.

Quando lo combini con React's useRef(), puoi farlo nel modo seguente.

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

Quando si desidera scorrere fino a un componente React, è necessario inoltrare il riferimento all'elemento renderizzato. Questo articolo approfondirà il problema .


Questo è molto meglio. Inizialmente stavo facendo, (ref) => window.scrollTo(0, ref.current.offsetTop) ma poi ottenevo solo un piccolo offset dall'alto e non arrivavo al bersaglio. Credo che ciò sia dovuto al fatto che la posizione dell'arbitro era stata calcolata all'inizio e quindi non aggiornata. Il tuo suggerimento ha risolto il mio problema, mentre la risposta accettata no.
Willy

1

Cosa ha funzionato per me:

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

Solo un avvertimento, non sono riuscito a far funzionare queste soluzioni sui componenti dell'interfaccia utente dei materiali. Sembra che non abbiano la currentproprietà.

Ho appena aggiunto uno divspazio vuoto tra i miei componenti e ho impostato il ref ref su quello.


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

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


0

L'ho usato all'interno di una funzione onclick per scorrere senza problemi fino a un div in cui il suo ID è "step2Div".

let offset = 100;
window.scrollTo({
    behavior: "smooth",
    top:
    document.getElementById("step2Div").getBoundingClientRect().top -
    document.body.getBoundingClientRect().top -
    offset
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.