目录为站点查看者提供页面内容的摘要,使他们能够通过单击所需的标题快速导航到页面的各个部分。通常,目录是在文档和博客中实现的。
在本教程中,我们将学习如何创建一个粘性目录,动态列出页面上的可用标题,突出显示活动标题。当我们滚动浏览我们的文章时,当一个标题在屏幕上可见时,它将在 TOC 中突出显示,如下面的 gif 所示:
要学习本教程,您应该熟悉 React 和 React Hooks。您还应该在系统上安装 Node.js。本教程的完整代码可在GitHub上找到。让我们开始吧!
设置反应
创建 TOC 组件
找到页面上的标题
层次结构中的链接和列表标题
查找并突出显示当前活动的标题
使用 Intersection Observer API 观察活动标题
突出显示活动标题
突出显示 TOC 项的缺点
对于本教程,我创建了一个入门存储库,其中包含了我们将用于创建目录的代码。首先,我们需要克隆 repo。为此,请在终端中运行以下命令:
$ git clone -b starter https://github.com/Tammibriggs/table-of-content.git $ cd 目录 $ npm 安装
当我们使用$ npm start命令启动应用程序时,我们应该看到以下页面:
让我们从创建我们的 TOC 组件开始,它将是粘性的,并将驻留在我们屏幕的右侧。
在我们之前克隆的应用程序中,在目录中创建一个TableOfContent.js文件和一个tableOfContent.css文件src。将以下代码行添加到TableOfContent.js文件中:
// src/TableOfContent.js
导入'./tableOfContent.css'
功能表内容(){
返回 (
<导航>
)
}
导出默认 TableOfContent
在上面的代码中,请注意我们将文本包装在一个锚标记中。如何在Excel图表中添加水平线?excel表格怎么画水平线?在我们的 TOC 中,我们将添加功能,以便当我们单击一个标题时,它会将我们带到页面上的相应部分。
href通过在属性中传递我们想要导航到的部分的 ID,我们可以使用锚标记轻松完成此操作。因此,我们页面上的所有部分都必须包含一个 ID,我已经将其包含在Content.js文件中。
接下来,在文件中添加以下代码行tableOfContent.css :
// src/tableOfContent.css
导航{
宽度:220px;
最小宽度:220px;
填充:16px;
对齐自我:弹性开始;
位置:-webkit-sticky;
位置:粘性;
顶部:48px;
最大高度:计算(100vh - 70px);
溢出:自动;
边距顶部:150px;
}
导航里{
底部边距:15px;
}
现在,要显示此组件,请转到App.js文件并添加以下导入:
从'./TableOfContent'导入TableOfContent;
接下来,将App组件修改为如下所示:
// src/App.js
函数应用程序(){
返回 (
<内容/>
);
}
使用上面的代码,我们将在应用的右侧看到一个粘性组件。
要查找页面上的所有标题,我们可以使用querySelectorAlldocument 方法,该方法返回一个NodeList表示与指定选择器组匹配的元素列表。
下面的示例显示了我们将如何使用该querySelectorAll方法:
常量标题 = document.querySelectorAll(h2, h3, h4)
我们已指定h2、h3和h4作为选择器,它们是文章中使用的潜在标题。视频搜索引擎优化,如何提升您的网站SEO?我们不包括h1因为它主要用于页面的标题,并且我们希望我们的 TOC 只包含我们页面的子部分。
现在要查找标题,请在文件中添加以下导入TableOfContent.js:
从'react'导入{useEffect,useState};
接下来,在组件中,在 return 语句之前添加以下代码行:
// src/TableOfContent.js
const [标题,setHeadings] = useState([])
使用效果(()=> {
常量元素 = Array.from(document.querySelectorAll("h2, h3, h4"))
.map((elem) => ({
文本:elem.innerText,
}))
设置标题(元素)
}, [])
上面的代码会在我们的页面上找到所有指定的标题元素,然后将文本内容存储在状态中。
在上面的代码中,我们使用该Array.from方法从NodeList返回的querySelectorAll. 我们这样做是因为map我们上面使用的某些功能,例如 ,没有在 上实现NodeList。为了轻松处理找到的标题元素,我们将它们转换为数组。
现在,要在 TOC 中显示标题,请修改组件的 return 语句,使其类似于以下代码:
// src/TableOfContent.js
返回 (
<导航>
现在,当我们在浏览器中打开应用程序时,我们将看到以下内容:
现在,当我们单击目录中的标题时,它不会将我们带到正确的部分。您会注意到它们都在同一行,没有指示哪个是主标题或副标题。让我们解决这个问题。
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →
在TableOfContent组件中,将useEffectHook 修改为如下代码:
// src/TableOfContent.js
使用效果(()=> {
常量元素 = Array.from(document.querySelectorAll("h2, h3, h4"))
.map((elem) => ({
id:elem.id,
文本:elem.innerText,
级别:数字(elem.nodeName.charAt(1))
}))
设置标题(元素)
}, [])
除了我们找到的标题中的文本外,我们还向level状态添加了一个 ID 和一个属性。我们将 ID 传递给 TOC 文本的锚标记,这样当我们单击它时,我们将被带到页面的相应部分。最新消息:Apple正在为 M2 iPad Pro 测试 macOS 触摸优化版的mac然后,我们将使用该level属性在 TOC 中创建层次结构。
修改ul组件返回语句中的元素,TableOfContent如下所示:
// src/TableOfContent.js
在上面的代码中,除了将 ID 添加到href锚标签的属性之外,我们还添加了一个onClick事件,当触发该事件时,会调用该事件scrollIntoView以使浏览器平滑滚动到相应的部分。
在元素中li,我们调用属性。我们将使用这个我们将很快创建的特性来根据属性的值设置不同的类名。因此,我们可以为目录中的子标题赋予与主标题不同的样式。getClassName(heading.level)classNamelevel
接下来,要创建getClassName函数,请在组件外部添加以下代码TableOfContent:
// src/TableOfContent.js
const getClassName = (级别) => {
开关(级别){
案例2:
返回“头2”
案例3:
返回“头3”
案例4:
返回'head4'
默认:
返回空
}
}
现在,在 intableOfContent.css 文件中添加以下代码行:
// src/tableOfContent.css
.head3{
左边距:10px;
列表样式类型:圆形;
}
.head4{
左边距:20px;
列表样式类型:正方形;
}
使用上面的代码,当我们单击目录中的标题或副标题时,我们将被带到相应的部分。现在,我们的 TOC 中有一个标题层次结构:
当一个标题在我们的页面上可见时,我们希望在 TOC 中突出显示相应的文本。
为了检测标题的可见性,我们将使用Intersection Observer API,它提供了一种监视目标元素的方法,当元素到达预定义的位置时执行一个函数。
使用 Intersection Observer API,我们将创建一个自定义 Hook,它将返回活动标头的 ID。然后,我们将使用返回的 ID 突出显示 TOC 中的相应文本。
为此,在src目录中创建一个hook.js文件并添加以下代码行:
// src/hooks.js
从'react'导入{useEffect,useState,useRef};
导出函数 useHeadsObserver() {
常量观察者 = useRef()
const [activeId, setActiveId] = useState('')
使用效果(()=> {
const handleObsever = (条目) => {}
观察者.current =新的IntersectionObserver(handleObsever,{
rootMargin: "-20% 0% -35% 0px"}
)
return () => observer.current?.disconnect()
}, [])
返回 {activeId}
}
在上面的代码中,我们创建了一个新的 Intersection Observer 实例。我们传递了handleObsever回调和一个options对象,我们在其中指定了执行观察者回调的环境。
在object使用该rootMargin属性时,我们将根元素的顶部(当前是我们的整个页面)缩小了 20%,将底部元素缩小了 35%。因此,当页眉位于页面顶部 20% 和底部 35% 时,它不会被视为可见。
不要错过来自 LogRocket 的精选时事通讯The Replay
了解LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题
使用 React 的 useEffect优化应用程序的性能
在多个 Node 版本之间切换
了解如何使用 AnimXYZ 为您的 React 应用程序制作动画
探索 Tauri,一个用于构建二进制文件的新框架
比较NestJS 与 Express.js
observe让我们通过将它们传递给Intersection Observer的方法来指定我们想要观察的标题。我们还将修改handleObsever回调函数以在状态中设置相交标头的 ID。
为此,请将useEffectHook 修改为如下代码:
// src/hooks.js
使用效果(()=> {
const handleObsever = (条目) => {
entry.forEach((entry) => {
if (entry?.isIntersecting) {
setActiveId(entry.target.id)
}
})
}
观察者.current =新的IntersectionObserver(handleObsever,{
rootMargin: "-20% 0% -35% 0px"}
)
常量元素 = document.querySelectorAll("h2, h3", "h4")
elements.forEach((elem) => observer.current.observe(elem))
return () => observer.current?.disconnect()
}, [])
在TableOfContent.js文件中,使用以下代码导入创建的 Hook:
// src/TableOfContent.js
从 './hooks' 导入 { useHeadsObserver }
headings 现在,在组件中的状态之后调用 Hook TableOfContent:
// src/TableOfContent.js
常量 {activeId} = useHeadsObserver()
使用上面的代码,当标题元素相交时,它将与activeId.
要突出显示 TOC 中的活动标题,请通过添加以下样式属性来修改组件返回语句中元素的锚标记:li``TableOfContent
风格={{
fontWeight: activeId === heading.id ?“粗体”:“正常”
}}
现在,我们的锚标记将如下所示:
// src/TableOfContent.js
<一个
href={`#${heading.id}`}
onClick={(e) => {
e.preventDefault()
document.querySelector(`#${heading.id}`).scrollIntoView({
行为:“顺利”
})}}
风格={{
fontWeight: activeId === heading.id ?“粗体”:“正常”
}}
>
{标题.文本}
现在,当标题处于活动状态时,它将变为粗体。有了这个,我们就完成了创建带有标题突出显示的目录。
在向 TOC 添加项目突出显示时,需要牢记一些注意事项。一方面,没有标准的方法可以将此功能添加到 TOC。因此,在不同的网站上,实施方式是不同的,这意味着我们网站的用户必须了解我们的 TOC 是如何工作的。
此外,由于每个目录根据其下方的文本在每个标题之间具有不同的间距,因此我们对突出显示功能的实现可能不适用于所有标题。
向您的博客或文章添加目录可为网站访问者提供更好的体验。在本教程中,我们学习了如何创建带有突出显示项目的目录以指示每个活动标题,帮助您的用户浏览您的网站并改善您的整体用户体验