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

时间:2019-08-27 10:01:41

标签: javascript reactjs react-spring

我已经阅读了整个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和钩子进行尝试。

useRef被附加到滚动目标位置,以便从网站上限找到其偏移的顶部。

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

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

有人可以协助解决这个问题吗?

在线上没有太多解释,谢谢!

3 个答案:

答案 0 :(得分:1)

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

这样定义您的spring

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

然后使用setY函数启动弹簧,如下所示:

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

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

请注意,我们从window.scroll的{​​{1}}属性调用onFrame函数。

查看工作演示here

答案 1 :(得分:1)

最后通过 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

答案 2 :(得分:0)

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)确实会返回stop之外的set方法。但是我无法使其兼容。我将其发布到相关的github issue。如果您读过这篇文章,也许已经有了一个很好的答案:)

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


更新:

似乎stop fn实际上有些可疑,应该在v9 canary中解决。由于v9尚未稳定,因此尚未测试。