ChatGPT解决这个技术问题 Extra ChatGPT

如何滚动到一个元素?

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

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

  render() {

    return (
      <div>
        <div ref="test"></div>
      </div>)
  }
对于捆绑解决方案:npmjs.com/package/react-scroll-to-component

B
Ben Carp

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 月)。

字符串引用有一些问题,被认为是遗留问题,并且可能会在未来的某个版本中被删除。 [官方反应文档]

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 的孩子。您可以将该方法传递给不同的子组件,并从那里触发它。
l
lwdthe1

这对我有用

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

编辑:我想根据评论对此进行扩展。

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

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

在哪里放这个
在生命周期方法或构造函数中
奇迹般有效。以上都对我不起作用,这应该被接受!
为我工作,只需注意“开始”是“块”参数的默认值。
当@Ben Carp 的回答不起作用时,这对我有用。
R
Roman Maksimov

只需找到您已确定的元素的顶部位置 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)
J
Jose

我有一个简单的场景,当用户单击 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 中的元素。这非常有效!
谢谢。在测试其他解决方案之后,只有这能按我的预期工作。
简单直接的解决方案,完美运行。好工作!
T
Tanapruk Tangphianphan

您现在可以使用来自 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 模式有关吗?
B
Ben Carp

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 的返回类型声明为 [() => void, RefObject<HTMLInputElement>] 。然后您可以毫无问题地调用 executeScroll()
@kasztof,我是 TS 粉丝,但我听到一个强烈的意见,认为 TS 不应该用在 JS SOF 问题中,因为它会让非 TS 开发人员更难理解。我知道你面临的问题。您也可以将返回值转换为 const。我们可以在评论中或在答案末尾添加 TS 定义。
A
Afaq Ahmed Khan

使用 findDOMNode 最终将被弃用。

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

github eslint


请包含链接材料的相关部分,以防万一被删除,您的答案不会变得无用。
r
robinvdvleuten

最好的方法是使用 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) => window.scrollTo(0, ref.current.offsetTop) ,但后来只从顶部得到了一个小的偏移量而没有到达目标。我相信这是因为裁判的位置是在开始时计算出来的,然后没有更新。您的建议解决了我的问题,而接受的答案却没有。
F
Farshad J

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

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

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

A
Afaq Ahmed Khan

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

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

所以我能想到并完美工作的最简单的解决方案是执行以下操作

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

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

欢呼,希望它可以帮助别人


p
p-a-o-l-o

你可以这样尝试:

 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 传递给函数。
u
user3349907

这个解决方案在 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>

R
Raviteja

您可以使用类似 componentDidUpdate

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

我认为在反应中不首选使用元素 ID。它打破了虚拟dom概念
使用生命周期方法是在何时/何地运行代码的方法。但可能希望将您在此答案中看到的其他方法用于实际代码
b
bello hargbola

这是您可以用来解决此问题的类组件代码片段:

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

M
Mario Petrovic

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

您的答案可能会受益于链接、ScrollIntoViewOptions 的定义和示例用法。
A
Azametzin

按着这些次序:

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

当存在多个组件或引用传递很复杂时,此库 react-scroll-to 非常有用。
S
Suneth Thotagamuwa

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

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

在这里我猜你的页面有固定数量的元素,因为你已经硬编码了'offset'的值。如果页面中的元素是基于来自 API 的动态响应动态呈现的,您将如何解决滚动问题。
J
Jan Schultke

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

我使用 redux 形式。 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" })

}

整洁的!即使您从父级触发滚动,这也适用于滚动到嵌套元素。
S
Senthuran

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

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

上述方法对我有用。


B
Bruno Pintos

如果您想在页面加载时执行此操作,您可以使用 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>
      </>
   )
}

D
DINA TAKLIT

您可以将 useRefscrollIntoView 一起使用。

对要滚动到的元素使用 useRef:这里我想滚动到 PieceTabs 元素,这就是为什么我用 Box(div) 包装它,这样我就可以访问 dom 元素

您可能熟悉 refs 主要是作为访问 DOM 的一种方式。如果你将一个 ref 对象传递给 React,只要该节点发生变化,React 就会将其 .current 属性设置为相应的 DOM 节点。查看文档

...
const tabsRef = useRef()
...
<Box ref={tabsRef}>
   <PieceTabs piece={piece} value={value} handleChange={handleChange} />
</Box>
...

创建一个处理此滚动的函数:

  const handleSeeCompleteList = () => {
    const tabs = tabsRef.current
    if (tabs) {
      tabs.scrollIntoView({
        behavior: 'smooth',
        block: 'start',
      })
    }
  }

单击滚动到目标后,在所需元素上调用此函数:

 <Typography
  variant="body2"
  sx={{
    color: "#007BFF",
    cursor: "pointer",
    fontWeight: 500,
  }}
  onClick={(e) => {
    handleChange(e, 2);
    handleSeeCompleteList(); // here we go
  }}
>
  Voir toute la liste
</Typography>;

https://i.stack.imgur.com/OrjAh.gif


R
Robert O'Toole
<div id="componentToScrollTo"><div>

<a href='#componentToScrollTo'>click me to scroll to this</a>

这就是你所需要的。


A
Artur Barseghyan

什么对我有用:

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

S
Steve

请注意,我无法让这些解决方案在 Material UI 组件上运行。看起来他们没有 current 属性。

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


U
User59

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


H
Halil Şağan

这是我的解决方案:

我在主 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>

c
colining

也许有人会遇到像我这样的情况

https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node

如何测量 DOM 节点?测量 DOM 节点的位置或大小的一种基本方法是使用回调 ref。每当 ref 附加到不同的节点时,React 都会调用该回调。这是一个小演示:

function MeasureExample() {
  const [height, setHeight] = useState(0);

  const measuredRef = useCallback(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);// you can scroll in this line 
    }
  }, []);

  return (
    <>
      <h1 ref={measuredRef}>Hello, world</h1>
      <h2>The above header is {Math.round(height)}px tall</h2>
    </>
  );
}

在这个例子中我们没有选择 useRef,因为一个对象 ref 没有通知我们当前 ref 值的变化。使用回调 ref 可确保即使子组件稍后显示测量节点(例如响应单击),我们仍会在父组件中收到有关它的通知并可以更新测量值。

请注意,我们将 [] 作为依赖数组传递给 useCallback。这确保了我们的 ref 回调在重新渲染之间不会改变,因此 React 不会不必要地调用它。

在这个例子中,回调 ref 只会在组件安装和卸载时被调用,因为渲染的组件在任何重新渲染过程中都保持存在。如果您想在组件调整大小时收到通知,您可能需要使用 ResizeObserver 或基于它构建的第三方 Hook。


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

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

S
Scott Lexium

这是我发现为我工作的最简单的方法。只需使用普通的 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>