【问题标题】:Scrolling scrollable div freezes moving content滚动可滚动 div 冻结移动内容
【发布时间】:2021-07-19 18:02:28
【问题描述】:

当我垂直滚动移动的 div 时,一些内容会冻结。我想知道如何解决这个问题。它也不一致,因为单击开始/停止按钮有时会在几秒钟内解决问题。很困惑。

import { useEffect, useRef, useState } from "https://cdn.skypack.dev/react"
import ReactDOM from "https://cdn.skypack.dev/react-dom"

const Graph = ({ references: { trackerRef, wholeRef } }) => {
    return (
        <div
            ref={wholeRef}
            style={{
                overflow: 'scroll',
                height: '400px',
                backgroundColor: '#333',
                cursor: 'default',
                userSelect: 'none'
            }}
        >
            <div style={{ position: 'relative' }}>
                <div>
                    {(() => {
                        const items = []

                        for (let i = 1; i < 100; i++) {
                            items.push(
                                <div
                                    key={i}
                                    style={{
                                        position: 'absolute',
                                        left: i * 1000,
                                        height: '100%',
                                        display: 'flex',
                                    }}
                                >
                                    <div
                                        style={{
                                            width: '1px',
                                            backgroundColor: '#888',
                                        }}
                                    ></div>
                                    <div style={{ color: '#ddd', marginLeft: 8, fontSize: 14 }}>
                                        {i}s
                                    </div>
                                </div>
                            )
                        }

                        return items
                    })()}
                    {(() => {
                        const items = []

                        for (let i = 1; i < 1000; i++) {
                            if ((i * 100) % 1000 === 0) continue

                            items.push(
                                <div
                                    key={i}
                                    style={{
                                        position: 'absolute',
                                        left: i * 100,
                                        height: '100%',
                                        display: 'flex',
                                    }}
                                >
                                    <div
                                        style={{
                                            width: '1px',
                                            backgroundColor: '#555',
                                        }}
                                    ></div>
                                    <div style={{ color: '#aaa', marginLeft: 5, fontSize: 10 }}>
                                        {i * 100}ms
                                    </div>
                                </div>
                            )
                        }

                        return items
                    })()}
                    <div
                        ref={trackerRef}
                        style={{
                            position: 'absolute',
                            height: '100%',
                            display: 'flex',
                            width: '1px',
                            backgroundColor: 'lightgreen',
                        }}
                    ></div>
                </div>
                <div>
                    <div style={{ height: '2000px', width: '20px' }}></div>
                </div>
            </div>
        </div>
    )
}

const App = () => {
    const trackerRef = useRef(null)
    const wholeRef = useRef(null)
    const [paused, setPaused] = useState(false)
    const animationFrames = useRef([]).current
    const intervals = useRef([]).current
    const time = useRef(0)

    useEffect(() => {
        // Increase time when unpaused
        intervals.push(setInterval(() => !paused && (time.current += 1), 1))
    }, [paused])

    useEffect(() => {
        const refreshTrackbar = () => {
            if (trackerRef.current && wholeRef.current && !paused) {
                trackerRef.current.style.left = time.current + 'px'
                wholeRef.current.scrollLeft = time.current - 100
                requestAnimationFrame(refreshTrackbar)
            }
        }

        animationFrames.push(requestAnimationFrame(refreshTrackbar))
    }, [paused])

    return (
        <>
            <h1>Scrollbug</h1>
            <button
                onClick={() => {
                    if (paused) {
                        setPaused(false)
                    } else {
                        setPaused(true)
                        animationFrames.forEach(frame => cancelAnimationFrame(frame))
                        intervals.forEach(interval => clearInterval(interval))
                    }
                }}
            >
                {paused ? 'Start' : 'Stop'}
            </button>
            <br />
            <br />
            <Graph references={{ trackerRef, wholeRef }} />
        </>
    )
}

ReactDOM.render(<App />, document.getElementById("root"))

这是一个自己测试问题的代码笔

https://codepen.io/springer268/pen/PomjVvw

编辑:所以我在我的 mac 上尝试了这个 codepen,并且没有发生错误,这让我相信这是 Chrome 版本/平台特定的问题,而不是我的问题。

【问题讨论】:

  • 你写的函数是非常昂贵的操作,除此之外滚动事件是一个重载,它因此而滞后,这里有一些技巧可以帮助减少它,不要使用for循环在 React 组件内部,它每次都会执行,在组件渲染之前尝试只获取一次值
  • 好主意。将循环重构为它们自己的组件,性能似乎更好。不幸的是,仍然经历着寒冷。

标签: css reactjs


【解决方案1】:

我不太确定如何让它停止冻结,但是如果您在 #root 中添加了一个高度比横向滚动 div 更大的 overflow:scroll;,您可以滚动它而不会冻结。

将横向滚动 div 设置为特定高度,overflow-y: hidden; 也会有所帮助。

一种解决方法,但它有效。

【讨论】:

  • 这不是问题所在
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-02
  • 1970-01-01
相关资源
最近更新 更多