Bagaimana cara menggulir ke suatu elemen?

181

Saya memiliki widget obrolan yang menarik serangkaian pesan setiap kali saya menggulir ke atas. Masalah yang saya hadapi sekarang adalah slider tetap diperbaiki di atas ketika pesan dimuat. Saya ingin fokus pada elemen indeks terakhir dari array sebelumnya. Saya menemukan bahwa saya dapat membuat referensi dinamis dengan melewati indeks, tetapi saya juga perlu tahu apa fungsi gulir yang digunakan untuk mencapai itu

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

  render() {

    return (
      <div>
        <div ref="test"></div>
      </div>)
  }
edmamerto
sumber
1
Untuk solusi yang dibundel: npmjs.com/package/react-scroll-to-component
tokland

Jawaban:

303

Bereaksi 16.8 +, Komponen fungsional

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

Klik di sini untuk demo lengkap tentang StackBlits

Bereaksi 16.3 +, Komponen kelas

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. 

}

Komponen kelas - Ref callback

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

Jangan gunakan String ref.

String merusak kinerja, tidak dapat dikomposasikan, dan sedang dalam perjalanan keluar (Agustus 2018).

string ref memiliki beberapa masalah, dianggap sebagai warisan, dan kemungkinan akan dihapus di salah satu rilis mendatang. [Dokumentasi Bereaksi Resmi]

resource1 resource2

Opsional: Smoothe scroll animation

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

Memberikan referensi kepada seorang anak

Kami ingin ref dilampirkan ke elemen dom, bukan ke komponen reaksi. Jadi ketika meneruskannya ke komponen anak, kita tidak bisa menyebutkan nama prop.

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

Kemudian pasang prop ref ke elemen dom.

const ChildComp = (props) => {
    return <div ref={props.refProp} />
}
Ben Carp
sumber
5
window.scrollTo(0, offsetTop)adalah opsi yang lebih baik dengan dukungan yang lebih baik di antara browser saat ini
MoMo
1
Bisa memastikan Anda konsisten dalam contoh Anda. Kita mulai dari myRef, pergi dengan domRef, dan diakhiri dengan tesNode? Itu cukup membingungkan
Louis Lecocq
4
Jelas setelah fakta, tetapi penting untuk menyebutkan bahwa ini hanya berfungsi untuk elemen DOM asli dan bukan sembarang komponen Bereaksi.
jpunk11
1
@ jpunk11 Saya baru saja memperbarui jawaban saya. Jawaban yang diperbarui menjelaskan cara menggulir ke elemen dom yang ada di komponen kelas anak.
Ben Carp
2
@SimonFranzen Lihatlah jawaban saya yang diperbarui - TLDR - case komponen kelas. Ketika scrollToMyRef dipanggil, itu akan bergulir ke anak yang dilampirkan oleh Anda. Anda dapat meneruskan metode ini ke komponen anak yang berbeda, dan memicunya dari sana.
Ben Carp
55

ini bekerja untuk saya

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

EDIT: Saya ingin memperluas ini berdasarkan komentar.

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

<div ref={scrollTo}>Item</div>
chii
sumber
1
di mana harus meletakkan ini
su_sundariya
dalam metode siklus hidup atau konstruktor
su_sundariya
1
Bekerja seperti pesona. Tidak ada satu pun di atas yang tidak berfungsi untuk saya, ini harus diterima jawaban!
Shin
1
Berhasil bagi saya, perlu diketahui bahwa 'mulai' adalah nilai default dari parameter 'blok'.
Liron Lavi
Ini bekerja untuk saya ketika jawaban @Ben Carp tidak.
Jason Masters
37

Cukup temukan posisi teratas elemen yang telah Anda tentukan https://www.w3schools.com/Jsref/prop_element_offsettop.asp lalu gulir ke posisi ini melalui scrollTometode https://www.w3schools.com/Jsref/met_win_scrollto.asp

Sesuatu seperti ini seharusnya bekerja:

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

MEMPERBARUI:

sejak Bereaksi v16.3 yang React.createRef()lebih disukai

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
sumber
2
Ini jawaban yang lebih baik. Menggunakan ReactDOM.findDomNode()adalah praktik yang lebih baik - karena Bereaksi ulang membuat komponen, div yang Anda dapatkan dengan ID-nya mungkin tidak ada pada saat Anda memanggil fungsi
Good Idea
4
Menurut dokumentasi resmi Anda harus mencoba untuk tidak menggunakan findDOMNode. Dalam kebanyakan kasus, Anda dapat melampirkan referensi ke simpul DOM dan menghindari penggunaan findDOMNodesama sekali.
Facyo Kouch
1
Perhatikan bahwa penggunaan this.refs oleh pemetaan string sudah usang, lihat: stackoverflow.com/questions/43873511/…
Himmet Avsar
1
Catatan: Saya harus menggunakan this.myRef.current.scrollIntoView()bukan window.scrollTo(0, this.myRef).
Babbz77
14

Menggunakan findDOMNode pada akhirnya akan ditinggalkan.

Metode yang disukai adalah menggunakan referensi panggil balik.

github eslint

sww314
sumber
3
Harap sertakan bagian yang relevan dari materi yang ditautkan sehingga dalam kasus yang dihapus jawaban Anda tidak menjadi sia-sia.
totymedli
12

Anda sekarang dapat menggunakan useRefdari API kait reaksi

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

pernyataan

let myRef = useRef()

komponen

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

Menggunakan

window.scrollTo({ behavior: 'smooth', top: myRef.current.offsetTop })
Tanapruk Tangphianphan
sumber
Saya mencoba menggunakan kode Anda. Saya bisa melihat, console.logbahwa itu menjalankan window.scrollTopernyataan Anda (disesuaikan untuk kasus saya) tetapi belum bergulir. Mungkinkah ini terkait dengan fakta bahwa saya menggunakan React Bootstrap Modal?
robertwerner_sf
9

Anda juga dapat menggunakan scrollIntoViewmetode untuk menggulir ke elemen yang diberikan.

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

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

Saya mungkin terlambat ke pesta, tetapi saya mencoba menerapkan referensi dinamis untuk proyek saya dengan cara yang tepat dan semua jawaban yang saya temukan sampai tahu tidak cukup memuaskan keinginan saya, jadi saya datang dengan solusi yang saya pikir adalah sederhana dan menggunakan cara reaksi asli dan direkomendasikan untuk membuat referensi.

kadang-kadang Anda menemukan bahwa cara dokumentasi ditulis mengasumsikan bahwa Anda memiliki jumlah penayangan yang diketahui dan dalam banyak kasus jumlah ini tidak diketahui sehingga Anda memerlukan cara untuk menyelesaikan masalah dalam kasus ini, buat referensi dinamis untuk jumlah penayangan yang tidak diketahui yang Anda butuhkan untuk ditampilkan di kelas

jadi solusi paling sederhana yang bisa saya pikirkan dan bekerja dengan sempurna adalah dengan melakukan sebagai berikut

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

dengan cara itu gulungan akan menuju ke baris apa pun yang Anda cari ..

bersorak dan berharap itu membantu orang lain

Miguel Sedek
sumber
8

Jul 2019 - Pengait / fungsi khusus

Sebuah kait / fungsi khusus dapat menyembunyikan detail implementasi, dan menyediakan API sederhana untuk komponen Anda.

Bereaksi 16.8 + Komponen Fungsional

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

  return [executeScroll, htmlElRef]
}

Gunakan dalam komponen fungsional apa pun.

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

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

demo penuh

Bereaksi 16.3 + Komponen kelas

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

  return {executeScroll, htmlElRef}
}

Gunakan dalam komponen kelas apa pun.

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

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

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

Demo penuh

Ben Carp
sumber
7

Anda dapat mencoba cara ini:

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

 render(){
  return(
      <h2 ref={elem => (this.gate = elem)}>Payment gate</h2>
 )}
jirina Brezinova
sumber
Solusi yang bagus, meskipun Anda mungkin menginginkan e.offsetTop daripada this.gate.offsetTop dan kemudian meneruskan this.gate ke fungsi.
KingOfHypocrites
5

Anda dapat menggunakan sesuatu seperti componentDidUpdate

componentDidUpdate() {
  var elem = testNode //your ref to the element say testNode in your case; 
  elem.scrollTop = elem.scrollHeight;
};
Raviteja
sumber
3
Saya pikir menggunakan elemen id tidak disukai dalam bereaksi. Itu merusak konsep dom virtual
iamsaksham
Menggunakan metode siklus hidup adalah cara untuk pergi sejauh KAPAN / DI MANA untuk menjalankan kode. Tetapi mungkin ingin menggunakan metodologi lain yang Anda lihat dalam jawaban ini untuk kode aktual
Dameo
3

Saya memiliki skenario sederhana, Ketika pengguna mengklik item menu di Material UI Navbar saya ingin menggulirkannya ke bagian halaman. Saya bisa menggunakan ref dan thread mereka melalui semua komponen tapi saya benci threading props props beberapa komponen karena itu membuat kode rapuh.

Saya baru saja menggunakan vanilla JS di komponen reaksi saya, ternyata berfungsi dengan baik. Menempatkan ID pada elemen yang ingin saya gulir ke dan di komponen header saya, saya baru saja melakukan ini.

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

Ikuti langkah ini:

1) Pasang:

npm install react-scroll-to --save

2) Impor paket:

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

3) Penggunaan:

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

Berikut ini potongan kode Komponen Kelas yang dapat Anda gunakan untuk menyelesaikan masalah ini:

Pendekatan ini menggunakan referensi dan juga menggulir dengan lancar ke target referensi

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
sumber
2

Cara terbaik adalah menggunakan element.scrollIntoView({ behavior: 'smooth' }) . Ini menggulir elemen ke tampilan dengan animasi yang bagus.

Ketika Anda menggabungkannya dengan React's useRef(), itu bisa dilakukan dengan cara berikut.

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

Saat Anda ingin menggulir ke komponen Bereaksi, Anda perlu meneruskan referensi ke elemen yang diberikan. Artikel ini akan masuk lebih dalam ke masalah .

robinvdvleuten
sumber
Ini jauh lebih baik. Saya awalnya melakukan (ref) => window.scrollTo(0, ref.current.offsetTop) tetapi kemudian hanya mendapatkan offset kecil dari atas dan tidak sampai pada target. Saya percaya ini karena lokasi wasit adalah seseorang yang dihitung pada awalnya dan kemudian tidak diperbarui. Saran Anda memperbaiki masalah saya sementara jawaban yang diterima tidak.
Willy
1

Apa yang berhasil untuk saya:

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
sumber
1

Hanya kepala, saya tidak bisa mendapatkan solusi ini untuk bekerja pada komponen Material UI. Sepertinya mereka tidak memiliki currentproperti.

Saya baru saja menambahkan yang kosong di divantara komponen-komponen saya dan mengatur ref ref pada itu.

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

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

Saya menggunakan ini di dalam fungsi onclick untuk menggulir dengan lancar ke div di mana id-nya adalah "step2Div".

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