【问题标题】:How to scroll to an element using react-spring?如何使用 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

谁能帮忙解决这个问题?

网上解释不多,谢谢!

【问题讨论】:

    标签: javascript reactjs react-spring


    【解决方案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+ 更新
      猜你喜欢
      • 2020-11-30
      • 2019-10-18
      • 1970-01-01
      • 2019-03-20
      • 2011-06-27
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多