gpt4 book ai didi

javascript - 如何使用 React 实现滚动 spy

转载 作者:行者123 更新时间:2023-12-03 13:38:20 27 4
gpt4 key购买 nike

我想在没有 Bootstrap 的情况下实现一个scrollspy

网上查了很多代码,都是jQuery实现的。

如何仅使用React的力量来实现scrollspy

最佳答案

我制作了一个 React Wrapper (与 Render-Props 一起使用):

Live Codepen Example

<小时/>

const {useState, useEffect, useCallback, useRef} = React;

/**
*
* @param {Object} scrollParent [DOM node of scrollable element]
* @param {Array} _targetElements [Array of nodes to spy on]
*/
const spyScroll = (scrollParent, _targetElements) => {
if (!scrollParent) return false;

// create an Object with all children that has data-name attribute
const targetElements =
_targetElements ||
[...scrollParent.children].reduce(
(map, item) =>
item.dataset.name ? { [item.dataset.name]: item, ...map } : map,
{}
);

let bestMatch = {};

for (const sectionName in targetElements) {
if (Object.prototype.hasOwnProperty.call(targetElements, sectionName)) {
const domElm = targetElements[sectionName];
const delta = Math.abs(scrollParent.scrollTop - domElm.offsetTop); // check distance from top, takig scroll into account

if (!bestMatch.sectionName)
bestMatch = { sectionName, delta };

// check which delet is closest to "0"
if (delta < bestMatch.delta) {
bestMatch = { sectionName, delta };
}
}
}

// update state with best-fit section
return bestMatch.sectionName;
};




/**
* Given a parent element ref, this render-props function returns
* which of the parent's sections is currently scrolled into view
* @param {Object} sectionsWrapperRef [Scrollable parent node React ref Object]
*/
const CurrentScrolledSection = ({ sectionsWrapperRef, children }) => {
const [currentSection, setCurrentSection] = useState();

// adding the scroll event listener inside this component, and NOT the parent component, to prever re-rendering of the parent component when
// the scroll listener is fired and the state is updated, which causes noticable lag.
useEffect(() => {
const wrapperElm = sectionsWrapperRef.current;
if (wrapperElm) {
wrapperElm.addEventListener('scroll', e => setCurrentSection(spyScroll(e.target)));
setCurrentSection(spyScroll(wrapperElm));
}

// unbind
return () => wrapperElm.removeEventListener('scroll', throttledOnScroll)
}, []);

return children({ currentSection });
};

function App(){
const sectionsWrapperRef = useRef()
return <CurrentScrolledSection sectionsWrapperRef={sectionsWrapperRef}>
{({ currentSection }) => <div ref={sectionsWrapperRef}>
<section
data-name="section-a"
className={currentSection === "section-a" ? 'active' : ''}
>Section A</section>
<section
data-name="section-b"
className={currentSection === "section-b" ? 'active' : ''}
>Section B</section>
<section
data-name="section-c"
className={currentSection === "section-c" ? 'active' : ''}
>Section C</section>
</div>
}
</CurrentScrolledSection>
}


ReactDOM.render(
<App />,
document.getElementById('root')
)
html, body, #root{ height: 95%; overflow:hidden; }

#root > div{
padding-bottom:20em;
height: 100%;
overflow:auto;
box-sizing: border-box;
}

section{
height: 50vh;
border-bottom: 1px solid red;
}

section.active{ background:lightyellow; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.0/umd/react-dom.production.min.js"></script>
<div id='root'></div>

它并不完美,因为滚动方向确实很重要,因为它暗示了用户的意图。

关于javascript - 如何使用 React 实现滚动 spy ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48966691/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com