Skip to content

Instantly share code, notes, and snippets.

@teal-front
Last active December 17, 2022 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teal-front/df554d858b28f48ad7c15f3ac2d85cf6 to your computer and use it in GitHub Desktop.
Save teal-front/df554d858b28f48ad7c15f3ac2d85cf6 to your computer and use it in GitHub Desktop.
common interaction
import React from 'react';
import classNames from 'classnames';
/**
* 点菜单,滚动到内容区的固定位置
*/
export function ScrollToView() {
const header = React.useRef(null);
const anchor1 = React.useRef(null);
const anchor2 = React.useRef(null);
const anchor3 = React.useRef(null);
const [fixed, setFixed] = React.useState(false);
const [active, setActive] = React.useState(1);
React.useEffect(() => {
const entryList = [
header.current,
anchor1.current,
anchor2.current,
anchor3.current,
]
// https://usefulangle.com/post/118/javascript-intersection-observer
// https://usefulangle.com/post/113/javascript-detecting-element-visible-during-scroll
const observer = new IntersectionObserver(function(entries) {
for(const entry of entries) {
if (entry.target === header.current) {
setFixed(entry.intersectionRatio === 0);
} else {
for(const anchor of entryList.slice(1).reverse()) {
if (entry.target === anchor && entry.intersectionRatio === 1) {
setActive(entryList.indexOf(anchor));
}
}
}
}
}, {threshold: [0, 1]});
entryList.forEach(entry => {
observer.observe(entry);
});
}, []);
// 使用JS来算出要滚动的高度,而不是使用a[id=anchor],这样会被fixed的菜单挡住一部分
const scrollToAnchor = (dom) => {
const { top } = dom.getBoundingClientRect();
const tagHeight = 40;
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
// window.scrollTo(x, y)
window.scrollTo(0, top + tagHeight);
}
return (
<>
<div className="header" ref={header}>header</div>
{/* .tags本身要占有高度, 避免子元素fixed之后,出现高度的抽空 */}
<div className='tags'>
<div className={classNames("tags-to-be-fixed", { fixed })}>
<div className={classNames("tag", { active: active === 1 })} onClick={() => scrollToAnchor(anchor1.current)}>
tag-1
</div>
<div className="tag">tag-2</div>
<div className="tag">tag-3</div>
</div>
</div>
<div className="content">
<div className="content-1" ref={anchor1}>Lorem, ipsum dolor.</div>
<div className="content-2" ref={anchor2}>Lorem, ipsum dolor.</div>
<div className="content-3" ref={anchor3}>Lorem, ipsum dolor.</div>
</div>
</>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment