4

我已经阅读了整个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

任何人都可以帮助解决这个问题吗?

网上没有太多解释,谢谢!

4

3 回答 3

5

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>

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

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

在此处查看工作演示。

于 2019-08-27T14:07:20.643 回答
1
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 问题上。如果你读到这个,也许已经有一个很好的答案了:)

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


更新:

似乎stopfn 实际上有一些问题,应该在v9 canary中解决。由于 v9 还不稳定,因此尚未测试。

于 2019-10-10T16:22:05.153 回答
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

于 2021-03-01T14:04:55.090 回答