如何使用 react-spring 滚动到元素?

Posted

技术标签:

【中文标题】如何使用 react-spring 滚动到元素?【英文标题】:How to scroll to an element using react-spring? 【发布时间】:2019-12-31 11:47:22 【问题描述】:

我已经阅读了整个 react-spring 文档,但似乎没有明确的方法来做到这一点。

我的尝试:

import React,  useRef, useState  from "react"
import  animated, useSpring  from "react-spring"

const App = () => 
    const scrollDestinationRef = useRef()

    const [elementScroll, setElementScroll] = useState(false)

    const buttonClickHandler = () => setElementScroll(prevState => !prevState)

    const scrollAnimation = useSpring(
        scroll: elementScroll
            ? scrollDestinationRef.current.getBoundingClientRect().top
            : 0
    )

    return (
        <main>
            /* Click to scroll to destination */
            <animated.button
                onClick=buttonClickHandler
                scrollTop=scrollAnimation.scroll
                style=
                    height: "1000px",
                    width: "100%",
                    backgroundColor: "tomato"
                
            >
                Scroll to destination
            </animated.button>

            /* Scroll destination */
            <div
                ref=scrollDestinationRef
                style=
                    height: "200px",
                    width: "200px",
                    backgroundColor: "green"
                
            ></div>
        </main>
    )


export default App

我正在尝试使用 ref 和 hooks。

useRef 附加到滚动目的地,以便找到它与网站天花板的偏移顶部。

我使用useState 在点击状态之间切换以触发滚动。

我使用useSpring 触发从0 到滚动目标的滚动顶部的动画,也就是getBoundingClientRect().top

谁能帮忙解决这个问题?

网上解释不多,谢谢!

【问题讨论】:

【参考方案1】:

useSpring 返回一个设置/更新动画值的函数。您可以使用该函数为动画变量分配新值。然后,您可以使用onFrame 属性来更新滚动位置。

像这样定义你的spring

const [y, setY] = useSpring(() => (
    immediate: false,
    y: 0,
    onFrame: props => 
      window.scroll(0, props.y);
    ,
    config: config.slow,
  ));

然后使用setY函数启动spring,像这样:

 <button
        onClick=() => 
          setY( y: scrollDestinationRef.current.getBoundingClientRect().top );
        
      >
        Click to scroll
 </button>

当您单击按钮时,它将在您的 spring 中为 y 变量分配一个新值,并且每次更新都会调用 onFrame 函数。

请注意,我们从useSpring 中的onFrame 属性调用window.scroll 函数。

查看工作演示 here。

【讨论】:

非常感谢。当您在加载后按一次按钮后向上和向下滚动时,它不再起作用。它只在第一次工作。请问可以修改一下吗?【参考方案2】:
const targetElement = useRef(null)
const [, setY] = useSpring(() => ( y: 0 ))

let isStopped = false
const onWheel = () => 
  isStopped = true
  window.removeEventListener('wheel', onWheel)


const scrollToTarget = () => 
  const element = targetElement.current
  const value = window.scrollY + element.getBoundingClientRect().top

  window.addEventListener('wheel', onWheel)

  setY(
    y: value,
    reset: true,
    from:  y: window.scrollY ,
    onRest: () => 
      isStopped = false
      window.removeEventListener('wheel', onWheel)
    ,
    onFrame: props => 
      if (!isStopped) 
        window.scroll(0, props.y)
      
    
  )

此版本还允许用户通过使用wheel 事件来摆脱强制滚动。 (我个人讨厌强制滚动:D)

useSpring(fn) 除了set 之外,还返回一个stop 方法。但我无法让它与它一起工作。我将其发布到相关的github issue。如果你读到这个,也许已经有一个很好的答案了:)

目前它使用isStopped 标志的小解决方法。


更新:

似乎stop fn 确实有问题,应该在v9 canary 中解决。尚未测试,因为 v9 还不稳定。

【讨论】:

【参考方案3】:

终于在通过https://github.com/pmndrs/react-spring/issues/544 之后,Yannick Schuchmann 的回答对我有用,我只需将 onFrame 更改为 onChange

我为解决方案制作了一个自定义挂钩:https://github.com/TomasSestak/react-spring-scroll-to-hook

react-sring 版本:9.0.0-rc.3

【讨论】:

在同一链接上为 react-spring 9+ 更新

以上是关于如何使用 react-spring 滚动到元素?的主要内容,如果未能解决你的问题,请参考以下文章

React JS:如何在 react-spring 中使用响应式样式

如何反向运行 react-spring 动画?

将 react-spring 用于 react-native

React-Spring useTransition 将我的列表项打乱

React-Spring - 改变过渡动画速度

如何使用 jQuery 滚动到元素?