【问题标题】:How to scroll to an element?如何滚动到一个元素?
【发布时间】:2017-09-12 12:04:33
【问题描述】:

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

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

  render() {

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

【问题讨论】:

标签: javascript reactjs ecmascript-6


【解决方案1】:

只要找到你已经确定的元素的顶部位置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>)
}

更新:

由于React v16.3首选React.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>)
}

【讨论】:

  • 这是更好的答案。使用ReactDOM.findDomNode() 是更好的做法——因为 React 会重新渲染组件,所以在调用函数时,您只需通过其 ID 获取的 div 可能不存在
  • 根据官方文档,你应该尽量避免使用findDOMNode。在大多数情况下,您可以将 ref 附加到 DOM 节点并完全避免使用 findDOMNode
  • 请注意,不推荐使用 this.refs 通过字符串映射,请参阅:stackoverflow.com/questions/43873511/…
  • 注意:我必须使用this.myRef.current.scrollIntoView() 而不是window.scrollTo(0, this.myRef)
【解决方案2】:

你可以使用componentDidUpdate之类的东西

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

【讨论】:

  • 我认为在反应中不推荐使用元素 id。它打破了虚拟 dom 的概念
  • 使用生命周期方法是在何时/何地运行代码的方法。但可能希望将您在此答案中看到的其他方法用于实际代码
【解决方案3】:

使用 findDOMNode 最终将被弃用。

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

github eslint

【讨论】:

  • 请包含链接材料的相关部分,以防万一被删除,您的答案不会变得无用。
【解决方案4】:

你可以试试这个方法:

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

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

【讨论】:

  • 很好的解决方案,尽管您可能需要 e.offsetTop 而不是 this.gate.offsetTop 然后将 this.gate 传递给函数。
【解决方案5】:

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

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

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

【讨论】:

    【解决方案6】:

    React 16.8 +,函数式组件

    const ScrollDemo = () => {
       const myRef = useRef(null)
    
       const executeScroll = () => myRef.current.scrollIntoView()    
       // run this function from an event handler or an effect to execute scroll 
    
       return (
          <> 
             <div ref={myRef}>Element to scroll to</div> 
             <button onClick={executeScroll}> Click to scroll </button> 
          </>
       )
    }
    
    

    Click here for a full demo on StackBlits

    React 16.3 +,类组件

    class ReadyToScroll extends Component {
        constructor(props) {
            super(props)
            this.myRef = React.createRef()  
        }
    
        render() {
            return <div ref={this.myRef}>Element to scroll to</div> 
        }  
    
        executeScroll = () => this.myRef.current.scrollIntoView()
        // run this method to execute scrolling. 
    }
    

    类组件 - Ref 回调

    class ReadyToScroll extends Component {  
        render() {
            return <div ref={ (ref) => this.myRef=ref }>Element to scroll to</div>
        } 
    
        executeScroll = () => this.myRef.scrollIntoView()
        // run this method to execute scrolling. 
    }
    

    不要使用字符串引用。

    字符串引用会损害性能,不可组合,并且即将淘汰(2018 年 8 月)。

    字符串引用有一些问题,被认为是遗留的,并且很可能 在将来的版本之一中删除。 [官方 React 文档]

    resource1resource2

    可选:平滑滚动动画

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

    将 ref 传递给孩子

    我们希望 ref 附加到 dom 元素,而不是 react 组件。因此,当将它传递给子组件时,我们不能命名 prop ref。

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

    然后将 ref 属性附加到一个 dom 元素。

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

    【讨论】:

    • window.scrollTo(0, offsetTop) 是更好的选择,在当前浏览器中得到更好的支持
    • 可以确保您在示例中保持一致。我们从 myRef 开始,使用 domRef,并以 tesNode 结束?这很令人困惑
    • 事后很明显,但重要的是要提到这仅适用于原生 DOM 元素,而不适用于任何 React 组件。
    • @jpunk11 我刚刚更新了我的答案。更新后的答案解释了如何滚动到子类组件中的 dom 元素。
    • @SimonFranzen 看看我更新的答案 - TLDR - 类组件案例。当调用 scrollToMyRef 时,它将滚动到您附加 ref 的孩子。您可以将方法传递给不同的子组件,并从那里触发它。
    【解决方案7】:

    这对我有用

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

    编辑:我想在 cmets 的基础上对此进行扩展。

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

    【讨论】:

    • 把这个放在哪里
    • 在生命周期方法或构造函数中
    • 像魅力一样工作。以上都对我不起作用,这应该被接受!
    • 为我工作,只需注意'start'是'block'参数的默认值。
    • 当@Ben Carp 的回答不起作用时,这对我有用。
    【解决方案8】:

    我可能迟到了,但我试图以正确的方式对我的项目实施动态引用,直到知道我找到的所有答案都不能满足我的喜好,所以我想出了一个解决方案我认为很简单,并使用本机和推荐的 react 方式来创建 ref。

    有时您会发现编写文档的方式假设您拥有已知数量的视图,并且在大多数情况下这个数字是未知的,因此您需要一种方法来解决这种情况下的问题,为未知数量的视图创建动态引用您需要在课堂上展示的视图

    所以我能想到并完美运行的最简单的解决方案是如下

    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
    

    这样滚动将转到您要查找的任何行..

    干杯,希望它可以帮助别人

    【讨论】:

      【解决方案9】:

      什么对我有用:

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

      【讨论】:

        【解决方案10】:

        您现在可以使用来自 react hook API 的useRef

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

        声明

        let myRef = useRef()
        

        组件

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

        使用

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

        【讨论】:

        • 我正在尝试使用您的代码。我可以通过console.log 看到它正在执行您的window.scrollTo 语句(针对我的情况进行了调整),但它不会滚动。这可能与我使用 React Bootstrap 模式有关吗?
        【解决方案11】:
         <div onScrollCapture={() => this._onScrollEvent()}></div>
        
         _onScrollEvent = (e)=>{
             const top = e.nativeEvent.target.scrollTop;
             console.log(top); 
        }
        

        【讨论】:

          【解决方案12】:

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

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

          React 16.8 + 功能组件

          const useScroll = () => {
            const elRef = useRef(null);
            const executeScroll = () => elRef.current.scrollIntoView();
          
            return [executeScroll, elRef];
          };
          

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

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

          full demo

          React 16.3 + 类组件

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

          在任何类组件中使用它。

          class ScrollDemo extends Component {
            constructor(props) {
              super(props);
              this.elScroll = utilizeScroll();
            }
          
            componentDidMount() {
              this.elScroll.executeScroll();
            }
          
            render(){
              return <div ref={this.elScroll.elRef}>Element to scroll to</div> 
            }
          } 
          

          Full demo

          【讨论】:

          • 对于任何使用 Typescript 的人,您应该将 useScroll 的返回类型声明为 [() =&gt; void, RefObject&lt;HTMLInputElement&gt;] 。然后你可以毫无问题地拨打executeScroll()
          • @kasztof,我是 TS 的粉丝,但我听到一个强烈的意见,认为 TS 不应该用于 JS SOF 问题,因为它会让非 TS 开发人员更难理解。我知道你面临的问题。您也可以将返回值转换为 const。我们可以在评论中或在答案末尾添加 TS 定义。
          【解决方案13】:

          按照以下步骤操作:

          1) 安装:

          npm install react-scroll-to --save
          

          2) 导入包:

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

          3)用法:

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

          【讨论】:

            【解决方案14】:

            请注意,我无法将这些解决方案用于 Material UI 组件。看起来他们没有current 属性。

            我刚刚在我的组件中添加了一个空的 div 并在其上设置了 ref 属性。

            【讨论】:

              【解决方案15】:

              这里是类组件代码sn-p,你可以用它来解决这个问题:

              这种方法使用了 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>
                  )
                }
              }
              

              【讨论】:

                【解决方案16】:

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

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

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

                【讨论】:

                • 我需要从组件 A 中的单击滚动到组件 B 中的元素。这非常有效!
                • 谢谢。在测试了其他解决方案之后,只有这能按我的预期工作。
                • 简单直接的解决方案,完美运行。干得好!
                【解决方案17】:

                对于其他阅读本文但对上述解决方案不太满意或只是想要一个简单的嵌入式解决方案的人,这个包对我有用:https://www.npmjs.com/package/react-anchor-link-smooth-scroll。祝黑客愉快!

                【讨论】:

                  【解决方案18】:

                  我在 onclick 函数中使用它平滑滚动到 id 为“step2Div”的 div。

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

                  【讨论】:

                  • 这里我猜你的页面有固定数量的元素,因为你已经硬编码了'offset'的值。如果页面中的元素是根据来自 API 的动态响应动态呈现的,您将如何解决滚动问题。
                  【解决方案19】:

                  最好的方法是使用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>
                      )
                  }
                  

                  当你想滚动到一个 React 组件时,你需要将 ref 转发给渲染的元素。 This article will dive deeper into the problem.

                  【讨论】:

                  • 这样更好。我最初是在做(ref) =&gt; window.scrollTo(0, ref.current.offsetTop) ,但后来只从顶部得到一个小的偏移量而没有到达目标。我相信这是因为裁判的位置是在开始时计算出来的,然后没有更新。您的建议解决了我的问题,而接受的答案却没有。
                  【解决方案20】:

                  如果您想在页面加载时执行此操作,您可以使用 useLayoutEffectuseRef

                  import React, { useRef, useLayoutEffect } from 'react'
                  
                  const ScrollDemo = () => {
                  
                     const myRef = useRef(null)
                  
                     useLayoutEffect(() => {
                        window.scrollTo({
                          behavior: "smooth",
                          top: myRef.current.offsetTop,
                        });
                      }, [myRef.current]);
                  
                     return (
                        <> 
                           <div ref={myRef}>I wanna be seen</div>
                        </>
                     )
                  }
                  

                  【讨论】:

                    【解决方案21】:

                    这是我的解决方案:

                    我在主 div 中放置了一个不可见的 div 并将其位置设为绝对。然后将顶部值设置为 -(header height) 并在此 div 上设置 ref。或者你可以只用 children 方法对该 div 做出反应。

                    到目前为止效果很好!

                    <div className="position-relative">
                            <div style={{position:"absolute", top:"-80px", opacity:0, pointerEvents:'none'}}  ref={ref}></div>
                    

                    【讨论】:

                      【解决方案22】:

                      在阅读了许多论坛后发现了一个非常简单的解决方案。

                      我使用 redux-form。 Urgo 映射 redux-from fieldToClass。出现错误时,我会导航到 syncErrors 列表中的第一个错误。

                      没有参考和第三方模块。简单的querySelector & scrollIntoView

                      handleToScroll = (field) => {
                      
                          const fieldToClass = {
                              'vehicleIdentifier': 'VehicleIdentifier',
                              'locationTags': 'LocationTags',
                              'photos': 'dropzoneContainer',
                              'description': 'DescriptionInput',
                              'clientId': 'clientId',
                              'driverLanguage': 'driverLanguage',
                              'deliveryName': 'deliveryName',
                              'deliveryPhone': 'deliveryPhone',
                              "deliveryEmail": 'deliveryEmail',
                              "pickupAndReturn": "PickupAndReturn",
                              "payInCash": "payInCash",
                          }
                      
                      document?.querySelector(`.${fieldToClasses[field]}`)
                               .scrollIntoView({ behavior: "smooth" })
                      
                      }
                      

                      【讨论】:

                        【解决方案23】:

                        为了自动滚动到特定元素,首先需要使用 document.getElementById 选择元素,然后我们需要使用 scrollIntoView() 进行滚动。请参考以下代码。

                           scrollToElement= async ()=>{
                              document.getElementById('id001').scrollIntoView();
                            } 
                        

                        上述方法对我有用。

                        【讨论】:

                          【解决方案24】:

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

                          在 header.js 中

                          function scrollToTestDiv(){
                                const divElement = document.getElementById('test');
                                divElement.scrollIntoView({ behavior: 'smooth' });
                              }
                          
                          <a class="nav-link" onClick={scrollToTestDiv}> Click here! </a>
                          

                          在 index.html 中

                          <div id="test"></div>
                          

                          【讨论】:

                            【解决方案25】:

                            如果有人在使用 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];
                            };
                            

                            【讨论】:

                              【解决方案26】:

                              这是我发现为我工作的最简单的方法。 只需使用普通的 javascript 语法,不需要太多包

                                const scrollTohowItWorks = () =>  window.scroll({
                                  top: 2000,
                                  left: 0,
                                  behavior: 'smooth'
                                });
                                
                                <NavLink onClick={scrollTohowItWorks} style={({ isActive }) => isActive? {color: '#e26702', fontWeight:'bold'}: { color: '#0651b3'}} to=''>Support</NavLink>
                              

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2011-08-18
                                • 1970-01-01
                                • 2021-11-30
                                • 1970-01-01
                                • 1970-01-01
                                • 2011-10-04
                                相关资源
                                最近更新 更多