gpt4 book ai didi

javascript - 使用 createRef 处理嵌套导航 + IntersectionObserver 的问题

转载 作者:行者123 更新时间:2023-12-01 15:43:50 28 4
gpt4 key购买 nike

我有一个intersectionObserver,可以观察一些部分并突出显示相应的导航项。但我只设法让“主要部分 Microsoft, Amazon 工作,而不是小部分 Define, Branding, Design, Deduction 。如下面的 gif 所示:
我希望它以这种方式构建的原因是,如果可以看到小节,我可以突出显示“主要”部分。
半工作演示:https://codesandbox.io/s/intersection-with-hooks-fri5jun1344-fe03x
Current
似乎我也可以使用小节复制和粘贴相同的功能。但是我很难围绕如何处理嵌套数据 + useRef + reducer。我想知道是否有人可以给我一个正确方向的指针。
这是所需效果的 gif。请注意,如果其中一个小节处于可见状态,主标题(放大镜、佳能)仍会突出显示:
一切都始于一个数据数组

const data = [
{
title: "Microsoft",
id: "microsoft",
color: "#fcf6f5",
year: "2020",
sections: ["define", "branding", "design", "deduction"]
},
{
title: "Amazon",
id: "amazon",
color: "#FFE2DD",
year: "2018",
sections: ["define", "design", "develop", "deduction"]
},
{
title: "Apple",
id: "apple",
color: "#000",
year: "2020",
sections: ["about", "process", "deduction"]
}
];
App.js 填充 data对象到 reduce 以创建 Refs
  const refs = data.reduce((refsObj, Case) => {
refsObj[Case.id] = React.createRef();
return refsObj;
}, {});
我的组件传入 props
          <Navigation
data={data}
handleClick={handleClick}
activeCase={activeCase}
/>
{data.map(item => (
<Case
key={item.id}
activeCase={activeCase}
setActiveCase={setActiveCase}
refs={refs}
data={item}
/>
))}
案例.js
export function Case({ data, refs, activeCase, setActiveCase }) {
const components = {
amazon: Amazon,
apple: Apple,
microsoft: Microsoft
};

class DefaultError extends Component {
render() {
return <div>Error, no page found</div>;
}
}
const Tag = components[data.id] || DefaultError;

useEffect(() => {
const observerConfig = {
rootMargin: "-50% 0px -50% 0px",
threshold: 0
};
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.target.id !== activeCase && entry.isIntersecting) {
setActiveCase(entry.target.id);
}
});
}, observerConfig);

observer.observe(refs[data.id].current);
return () => observer.disconnect(); // Clenaup the observer if unmount
}, [activeCase, setActiveCase, refs, data]);

return (
<React.Fragment>
<section
ref={refs[data.id]}
id={data.id}
className="section"
style={{ marginBottom: 400 }}
>
<Tag data={data} />
</section>
</React.Fragment>
);
}

我试过像这样映射小节,但我被困在这部分:
   const subRefs = data.map((refsObj, Case) => {
refsObj[Case] = React.createRef();
return refsObj;
}, {});

最佳答案

Working Example

我在尝试保持大部分逻辑完整的同时找到了解决方案。首先,您需要做的是将子引用(部分引用)存储在与案例引用相同的对象中。所以你需要一个额外的 reduce 函数来在 refs 对象中创建那些:

App.js

const refs = data.reduce((refsObj, Case) => { // Put this outside the render
const subRefs = Case.sections.reduce((subrefsObj, Section) => {
subrefsObj[Section] = React.createRef();
return subrefsObj;
}, {});

refsObj[Case.id] = {
self: React.createRef(), // self is the Case ref, like Apple, Microsoft...
subRefs // This is going to be the subrefs
};
return refsObj;
}, {});

然后你添加一个额外的状态来处理哪个子部分是事件的,比如 const [activeSection, setActiveSection] = React.useState();而且你把它放在任何你也使用的地方 activeCase .您需要这样做,因为您说过案例和部分需要独立工作。 (两者同时激活)。

Case.js

您需要将 subrefs 传递给子组件,因此您可以:
    <Tag data={data} subRefs={refs[data.id].subRefs} />

而且您还需要每个子引用的交集观察者。所以你的 useEffect 看起来像:
 useEffect(() => {
const observerConfig = {
rootMargin: "-50% 0px -50% 0px",
threshold: 0
};

const observerCallback = (entries, isCase) => {
const activeEntry = entries.find(entry => entry.isIntersecting);

if (activeEntry) {
if (isCase) setActiveCase(activeEntry.target.id);
else setActiveSection(activeEntry.target.id);
} else if (isCase) {
setActiveCase(null);
setActiveSection(null);
}
};

const caseObserver = new IntersectionObserver(
entries => observerCallback(entries, true),
observerConfig
);
caseObserver.observe(refs[data.id].self.current);

const sectionObserver = new IntersectionObserver(
entries => observerCallback(entries, false),
observerConfig
);

Object.values(refs[data.id].subRefs).forEach(subRef => {
sectionObserver.observe(subRef.current);
});

return () => {
caseObserver.disconnect();
sectionObserver.disconnect();
}; // Clenaup the observer if unmount
}, [refs, data]);

然后在您的 亚马逊/index.js , 微软/index.js 苹果/index.js 文件。你再次传递引用:
<Template
data={this.props.data}
caseSections={caseSections}
subRefs={this.props.subRefs}
/>

最后,在您的 模板.js 文件,您将拥有以下内容,以便您可以分配正确的引用:
const Template = props => {
return (
<React.Fragment>
<div
sx={{
background: "#eee",
transition: "background ease 0.5s"
}}
>
{props.data.sections &&
props.data.sections.map(subItem => (
<Container
ref={props.subRefs && props.subRefs[subItem]}
id={`${props.data.id}--${subItem}`}
key={subItem}
className="article"
>
<Section sectionId={subItem} caseSections={props.caseSections} />
</Container>
))}
</div>
</React.Fragment>
);
};

我相信大部分内容都包含在帖子中。您可以查看您的 forked working repo here

关于javascript - 使用 createRef 处理嵌套导航 + IntersectionObserver 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62220675/

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