Làm thế nào để cuộn đến một yếu tố?


180

Tôi có một tiện ích trò chuyện kéo lên một loạt các tin nhắn mỗi khi tôi cuộn lên. Vấn đề tôi gặp phải bây giờ là thanh trượt vẫn cố định ở trên cùng khi tải tin nhắn. Tôi muốn nó tập trung vào phần tử chỉ mục cuối cùng từ mảng trước. Tôi đã tìm ra rằng tôi có thể tạo các ref động bằng cách chuyển chỉ mục, nhưng tôi cũng cần biết nên sử dụng loại chức năng cuộn nào để đạt được điều đó

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

  render() {

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

1
Đối với một giải pháp đi kèm: npmjs.com/package/react-scroll-to-component
tokland

Câu trả lời:


301

Phản ứng 16.8 +, thành phần chức năng

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

Bấm vào đây để xem bản demo đầy đủ trên StackBlits

Phản ứng 16.3 +, thành phần lớp

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. 

}

Thành phần lớp - Gọi lại tham chiếu

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

Đừng sử dụng chuỗi refs.

Chuỗi giới thiệu gây hại cho hiệu suất, không thể kết hợp được và đang trên đường ra (tháng 8 năm 2018).

chuỗi giới thiệu có một số vấn đề, được coi là di sản và có khả năng bị xóa trong một trong các phiên bản tương lai. [Tài liệu phản ứng chính thức]

tài nguyên1 resource2

Tùy chọn: Làm mượt hoạt hình cuộn

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

Truyền ref cho một đứa trẻ

Chúng tôi muốn ref được gắn vào một phần tử dom chứ không phải thành phần phản ứng. Vì vậy, khi chuyển nó cho một thành phần con, chúng ta không thể đặt tên cho prop ref.

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

Sau đó gắn ref prop vào một phần tử dom.

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

5
window.scrollTo(0, offsetTop)là một tùy chọn tốt hơn với sự hỗ trợ tốt hơn giữa các trình duyệt hiện tại
MoMo

1
Có thể chắc chắn rằng bạn nhất quán trong mẫu mực của bạn. Chúng tôi đang bắt đầu từ myRef, đi với domRef và kết thúc bằng tesNode ?. Điều đó khá khó hiểu
Louis Lecocq

4
Rõ ràng sau thực tế, nhưng điều quan trọng là phải đề cập rằng điều này chỉ hoạt động cho các thành phần DOM gốc chứ không chỉ bất kỳ thành phần React nào.
j1111

1
@ jpunk11 Tôi vừa cập nhật câu trả lời của tôi. Câu trả lời cập nhật giải thích cách cuộn đến phần tử dom trong thành phần lớp con.
Cá chép Ben

2
@SimonFranzen Hãy xem câu trả lời được cập nhật của tôi - TLDR - trường hợp thành phần lớp. Khi scrollToMyRef được gọi, nó sẽ cuộn đến đứa trẻ mà bạn đã đính kèm ref. Bạn có thể truyền phương thức cho một thành phần con khác và kích hoạt nó từ đó.
Cá chép Ben

54

cái này làm việc cho tôi

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

EDIT: Tôi muốn mở rộng về điều này dựa trên các ý kiến.

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

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

1
nơi để đặt cái này
su_sundariya

trong phương pháp vòng đời hoặc hàm tạo
su_sundariya

1
Hoạt động như một lá bùa. Không có điều nào ở trên không phù hợp với tôi, điều này nên được chấp nhận câu trả lời!
Shin

1
Làm việc cho tôi, chỉ cần lưu ý rằng 'bắt đầu' là giá trị mặc định của tham số 'khối'.
Liron Lavi

Điều này làm việc cho tôi khi câu trả lời của @Ben Carp sẽ không.
Jason Masters

37

Chỉ cần tìm vị trí trên cùng của phần tử bạn đã xác định https://www.w3schools.com/Jsref/prop_element_offsettop.asp sau đó cuộn đến vị trí này thông qua scrollTophương thức https://www.w3schools.com/Jsref/met_win_scrollto.asp

Một cái gì đó như thế này sẽ hoạt động:

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

CẬP NHẬT:

kể từ React v16.3 , React.createRef()nó được ưu tiên

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
Đây là câu trả lời tốt hơn. Sử dụng ReactDOM.findDomNode()là cách thực hành tốt hơn - vì React kết xuất lại các thành phần, một div mà bạn chỉ cần nhận được bằng ID của nó có thể không tồn tại vào thời điểm bạn gọi hàm
Good Idea

4
Theo các tài liệu chính thức bạn nên cố gắng tránh sử dụng findDOMNode. Trong hầu hết các trường hợp, bạn có thể đính kèm một tham chiếu vào nút DOM và tránh sử dụng findDOMNodetất cả.
Facyo Kouch

1
Lưu ý rằng việc sử dụng this.refs bằng ánh xạ chuỗi không được chấp nhận, xem: stackoverflow.com/questions/43873511/ợi
Himmet Avsar

1
Lưu ý: Tôi đã phải sử dụng this.myRef.current.scrollIntoView()thay vì window.scrollTo(0, this.myRef).
Babbz77

14

Sử dụng findDOMNode cuối cùng sẽ bị phản đối.

Phương pháp ưa thích là sử dụng refs gọi lại.

github eslint


3
Vui lòng bao gồm phần có liên quan của tài liệu được liên kết để trong trường hợp bị xóa câu trả lời của bạn sẽ không trở nên vô dụng.
totymedli

12

Bây giờ bạn có thể sử dụng useReftừ API hook phản ứng

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

tờ khai

let myRef = useRef()

thành phần

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

Sử dụng

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

Tôi đang cố gắng sử dụng mã của bạn. Tôi có thể thấy, thông qua console.logđó nó đang thực thi window.scrollTotuyên bố của bạn (được điều chỉnh cho trường hợp của tôi) nhưng nó không cuộn. Điều này có thể liên quan đến thực tế là tôi đang sử dụng Modal Bootstrap Modal không?
robertwerner_sf

9

Bạn cũng có thể sử dụng scrollIntoViewphương thức để cuộn đến một phần tử nhất định.

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

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

9

Tôi có thể đến bữa tiệc muộn nhưng tôi đã cố gắng thực hiện các giới thiệu năng động cho dự án của mình theo cách phù hợp và tất cả câu trả lời tôi đã tìm thấy cho đến khi biết rằng không yên tĩnh thỏa mãn theo ý thích của tôi, vì vậy tôi đã đưa ra một giải pháp mà tôi nghĩ là đơn giản và sử dụng cách phản ứng tự nhiên và được đề nghị để tạo ref.

đôi khi bạn thấy rằng cách viết tài liệu giả định rằng bạn có số lượt xem đã biết và trong hầu hết các trường hợp, con số này không xác định nên bạn cần một cách để giải quyết vấn đề trong trường hợp này, hãy tạo các giới thiệu động cho số lượt xem chưa biết bạn cần thể hiện trong lớp

Vì vậy, giải pháp đơn giản nhất tôi có thể nghĩ ra và làm việc hoàn hảo là làm như sau

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

bằng cách đó, cuộn sẽ đi đến bất kỳ hàng nào bạn đang tìm kiếm ..

cổ vũ và hy vọng nó sẽ giúp người khác


8

Tháng 7 năm 2019 - Móc / chức năng chuyên dụng

Một hook / function chuyên dụng có thể ẩn chi tiết triển khai và cung cấp API đơn giản cho các thành phần của bạn.

Phản ứng 16.8 + Thành phần chức năng

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

  return [executeScroll, htmlElRef]
}

Sử dụng nó trong bất kỳ thành phần chức năng.

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

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

bản demo đầy đủ

Phản ứng thành phần lớp 16.3 +

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

  return {executeScroll, htmlElRef}
}

Sử dụng nó trong bất kỳ thành phần lớp.

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

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

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

Bản demo đầy đủ


7

Bạn có thể thử theo cách này:

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

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

Giải pháp tốt, mặc dù bạn có thể muốn e.offsetTop thay vì this.gate.offsetTop và sau đó chuyển this.gate cho hàm.
KingOfHypocrites

5

Bạn có thể sử dụng một cái gì đó như componentDidUpdate

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

3
tôi nghĩ rằng sử dụng id phần tử không được ưa thích trong phản ứng. Nó phá vỡ khái niệm dom ảo
iamsaksham

Sử dụng phương pháp vòng đời là cách để đi xa tới mức KHI / WHERE để chạy mã. Nhưng có lẽ muốn sử dụng các phương pháp khác mà bạn thấy trong câu trả lời này cho mã thực tế
Dameo 20/07/18

3

Tôi đã có một kịch bản đơn giản, Khi người dùng nhấp vào mục menu trong Thanh điều hướng giao diện người dùng vật liệu của tôi, tôi muốn cuộn chúng xuống phần trên trang. Tôi có thể sử dụng refs và xâu chúng qua tất cả các thành phần nhưng tôi ghét các đạo cụ tạo luồng cho nhiều thành phần vì điều đó làm cho mã dễ vỡ.

Tôi chỉ sử dụng vanilla JS trong thành phần phản ứng của mình, hóa ra nó hoạt động tốt. Đặt một ID trên thành phần mà tôi muốn cuộn đến và trong thành phần tiêu đề của tôi, tôi chỉ làm điều này.

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

2

Thực hiện theo các bước sau:

1) Cài đặt:

npm install react-scroll-to --save

2) Nhập gói:

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

3) Cách sử dụng:

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

2

Dưới đây là đoạn mã Thành phần Lớp bạn có thể sử dụng để giải quyết vấn đề này:

Cách tiếp cận này đã sử dụng ref và cũng cuộn trơn tru đến ref đích

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

Điều gì làm việc cho tôi:

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

Chỉ cần đề phòng, tôi không thể có được các giải pháp này để hoạt động trên các thành phần UI UI. Hình như họ không cócurrent tài sản.

Tôi chỉ cần thêm một khoảng trống divtrong số các thành phần của mình và đặt ref prop vào đó.


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

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


0

Tôi đã sử dụng cái này bên trong một hàm onclick để cuộn trơn tru đến một div trong đó id của nó là "step2Div".

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

0

Cách tốt nhất là sử dụng element.scrollIntoView({ behavior: 'smooth' }). Điều này cuộn phần tử vào xem với một hình ảnh động đẹp.

Khi bạn kết hợp nó với React's useRef(), nó có thể được thực hiện theo cách sau.

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

Khi bạn muốn cuộn đến một thành phần React, bạn cần chuyển tiếp ref đến phần tử được kết xuất. Bài viết này sẽ đi sâu hơn vào vấn đề .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.