突破编程_前端_JS编程实例(目录导航)
1 开发目标
目录导航组件旨在提供一个滚动目录导航功能,使得用户可以方便地通过点击目录条目快速定位到对应的内容标题位置,同时也能够随着滚动条的移动动态显示当前位置在目录中的位置:

2 详细需求
2.1 标题提取与目录生成
- 组件需要能够自动提取网页内容中的所有标题元素(如 h1, h2, h3 等)。
- 提取的标题需要按照其在网页中的层级关系(如 h1 后面跟着的 h2 是其子章节)进行组织,形成一个目录容器。
- 目录容器需以清晰、直观的方式展示给用户,允许用户通过点击目录条目进行导航。
2.2 滚动定位
- 当用户在目录容器中点击某个目录条目时,网页的滚动条需要动态移动到对应的标题位置,使得该标题出现在页面的最上方。
- 滚动过程应该平滑且快速,提升用户体验。
2.3 滚动条与目录条目交互
- 当用户滚动网页的滚动条时,目录容器中的对应目录条目应该能够实时更新状态,以指示当前所在位置。
- 当滚动条经过某个标题时,对应的目录条目应改变颜色(如高亮显示),以提醒用户当前的位置。
2.4 无滚动条情况处理
- 如果网页内容较少,没有出现滚动条,那么点击目录条目时不应触发任何滚动动作。
- 这种情况下,目录容器仍应正常显示,以供用户浏览网页内容的结构。
3 代码实现
首先创建一个 neat_directory.js 文件,该文件用于本组件的工具类、目录处理函数的代码构建。
(1)在具体的业务代码编写之前,先实现一个工具类以及一些工具方法,方便后面调用:
class CommonUtil {// 设置 DIV 中的文字为垂直居中static centerYTextInDiv(container) {container.style.display = 'flex';container.style.justifyContent = 'center';container.style.flexDirection = 'column';}// 判断 DIV 有无垂直滚动条static hasScrollbar(container) {var divStyle = window.getComputedStyle(container);var isOverflowing = container.scrollHeight > container.clientHeight;var isScrollbarVisible = isOverflowing &&(divStyle.overflow === 'scroll' || divStyle.overflow === 'auto' || divStyle.overflowY === 'scroll' || divStyle.overflowY === 'auto');return isScrollbarVisible;}
}
(2)接下来,开始定义目录节点类型,目录节点显示在目录区域:
class DirectoryNode {static LEVEL_OFFSET = 20; // 每个级别的目录节点偏移像素static NODE_HEIGHT = '30px'; // 目录节点高度static NODE_NAME_FONTSIZE = '14px'; // 默认目录标题字符串的字体大小static NODE_NAME_COLOR = '#000'; // 默认目录标题字符串字体颜色static NODE_NAME_ACTIVE_COLOR = 'red'; // 默认目录标题在激活情况下字符串字体颜色constructor(container, para) {this.container = container; // 本目录节点的容器this.para = para; // 配置参数,包含页面内容的容器、标题容器以及标题等级等this.init();}
上面代码定义了 DirectoryNode 的一些默认属性与成员变量,并且创建构造函数,该函数接收调用者传入的 DIV 容器,并且调用 render 方法。
在 render 方法中,需要渲染当前目录节点,并且还要定义点击事件:
render() {this.container.style.width = '100%';this.container.style.height = this.para.height ?? DirectoryNode.NODE_HEIGHT;this.container.style.fontSize = this.para.fontSize ?? DirectoryNode.NODE_NAME_FONTSIZE;this.container.style.color = this.para.color ?? DirectoryNode.NODE_NAME_COLOR;this.container.innerText = this.para.name;if (this.para.level > 1) { // 设置目录节点偏移this.container.style.paddingLeft = ((this.para.level - 1) * DirectoryNode.LEVEL_OFFSET) + 'px';}this.container.style.cursor = 'pointer';// 点击事件let that = this;this.container.onclick = function () {that.para.onClick.call(that.para.onClickObj, that);}}
然后需要对目录节点的激活与非激活状态以及目录跳转逻辑做实现:
// 目录节点激活并跳转对应目录位置activate() {this.container.style.color = DirectoryNode.NODE_NAME_ACTIVE_COLOR;}// 目录节点非激活deactivate() {this.container.style.color = this.para.color ?? DirectoryNode.NODE_NAME_COLOR;}// 目录跳转jump() {// 计算目标元素相对于父元素的位置 let targetElementRect = this.para.titleContainer.getBoundingClientRect();let parentRect = this.para.contentContainer.getBoundingClientRect();// 滚动到目标元素的顶部let offset = targetElementRect.top - parentRect.top + this.para.contentContainer.scrollTop;this.para.contentContainer.scrollTop = offset;}// 获取在页面内容的容器中,当前目录节点所对应的标题元素离顶部的距离getTopOffset() {let targetElementRect = this.para.titleContainer.getBoundingClientRect();let parentRect = this.para.contentContainer.getBoundingClientRect();return targetElementRect.top + parentRect.top;}
}
(3)在完成 DirectoryNode 的实现以后,开始创建目录类型 Directory :
class Directory {constructor(container, para) {this.container = container; // 传入的目录容器,用于渲染提取生成的目录this.para = para; // 配置参数,包含页面内容的容器this.nodes = []; // 目录节点集合this.jumpFlag=false; // 当前是否处于点击目录节点进行跳转的状态this.render();}
目录类型 Directory 的渲染函数 render 主要是获取页面内容中所有节点,遍历处理标题元素,然后创捷目录节点。此后,还需要定义页面内容的容器在滚动滚动轴时,触发目录变化的逻辑:
render() {// 清空目录容器this.container.innerHTML = '';// 获取页面内容中所有节点,遍历处理标题元素let containerNodes = this.para.contentContainer.childNodes;containerNodes.forEach(element => {if (!element.tagName) {return;}let tagName = element.tagName.toUpperCase();if (2 == tagName.length) {let tagName1 = tagName.slice(0, 1);let tagName2 = tagName.slice(1, 2);if ('H' == tagName1 && !isNaN(tagName2)) {let level = parseInt(tagName2); // 标题等级let directoryNodeContainer = document.createElement('div');this.container.appendChild(directoryNodeContainer);let nodePara = {"name": element.innerText,"level": level,"titleContainer": element,"contentContainer": this.para.contentContainer,"onClick": this.jumpTo,"onClickObj": this,}let node = new DirectoryNode(directoryNodeContainer, nodePara);this.nodes.push(node);}}});// 页面内容的容器在滚动滚动轴时,触发目录变化let that = this;this.para.contentContainer.addEventListener('scroll', function () {// 如果网页内容较少,没有出现滚动条,那么页面内容的容器在滚动滚动轴时,不做任何触发// 如果当前是处于点击目录节点进行跳转的状态,则不做处理if (!CommonUtil.hasScrollbar(that.para.contentContainer) || that.jumpFlag) {return;}// 判断当前内容属于哪一个目录节点let activeNode=null;for (let index = 0; index < that.nodes.length; index++) {const node = that.nodes[index];if(node.getTopOffset()<0 && index+1<that.nodes.length && that.nodes[index+1].getTopOffset()>0){activeNode = node;break;}}if(null == activeNode && that.nodes.length>0){activeNode = that.nodes[0];}that.nodes.forEach(element => {element.deactivate();});activeNode.activate();});}
在完成渲染函数 render 的实现后,即要实现点击后目录跳转的功能,注意:如果网页内容较少,没有出现滚动条,那么点击目录条目时不应触发任何滚动动作:
// 目录跳转jumpTo(node) {// 如果网页内容较少,没有出现滚动条,那么点击目录条目时不应触发任何滚动动作if (!CommonUtil.hasScrollbar(this.para.contentContainer)) {return;}this.jumpFlag=true; this.nodes.forEach(element => {element.deactivate();});node.activate();node.jump();// 延迟一段时间let that = this;setTimeout(function() { that.jumpFlag=false; }, 100); }
}
至此,整个目录导航功能的组件构建结束。
(4)完成目录导航功能的组件的代码编写后,可以创建 neat_directory.html 文件,调用该组件:
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta http-equiv="X-UA-Compatible" content="ie=edge" /><title>header tab</title><style>html {height: 100%;}body {margin: 0;height: 100%;}</style>
</head><body><div id="divMain" style="height: 100%;width: 100%;display: flex;"><div id="divDirectory" style="margin:10px;height: 500px;width: 300px;border: 1px solid #aaa;padding: 10px;"></div><div id="divContent" style="margin:10px;height: 500px;width: 600px;border: 1px solid #aaa;padding: 10px;overflow-y: auto;"><h1>1 第一章</h1><h2>1.1 第一章 第一节 </h2><span>组件需要能够自动提取网页内容中的所有标题元素(如 h1, h2, h3 等)。</span><span>提取的标题需要按照其在网页中的层级关系(如 h1 后面跟着的 h2 是其子章节)进行组织,形成一个目录容器。</span><span>目录容器需以清晰、直观的方式展示给用户,允许用户通过点击目录条目进行导航。</span><h3>1.1.1 第一章 第一节 第一段</h3><span>组件需要能够自动提取网页内容中的所有标题元素(如 h1, h2, h3 等)。</span><span>提取的标题需要按照其在网页中的层级关系(如 h1 后面跟着的 h2 是其子章节)进行组织,形成一个目录容器。</span><span>目录容器需以清晰、直观的方式展示给用户,允许用户通过点击目录条目进行导航。</span><h3>1.1.2 第一章 第一节 第二段</h3><span>组件需要能够自动提取网页内容中的所有标题元素(如 h1, h2, h3 等)。</span><span>提取的标题需要按照其在网页中的层级关系(如 h1 后面跟着的 h2 是其子章节)进行组织,形成一个目录容器。</span><span>目录容器需以清晰、直观的方式展示给用户,允许用户通过点击目录条目进行导航。</span><h1>2 第二章</h1><h2>2.1 第二章 第一节 </h2><span>组件需要能够自动提取网页内容中的所有标题元素(如 h1, h2, h3 等)。</span><span>提取的标题需要按照其在网页中的层级关系(如 h1 后面跟着的 h2 是其子章节)进行组织,形成一个目录容器。</span><span>目录容器需以清晰、直观的方式展示给用户,允许用户通过点击目录条目进行导航。</span><h3>2.1.1 第二章 第一节 第一段</h3><span>组件需要能够自动提取网页内容中的所有标题元素(如 h1, h2, h3 等)。</span><span>提取的标题需要按照其在网页中的层级关系(如 h1 后面跟着的 h2 是其子章节)进行组织,形成一个目录容器。</span><span>目录容器需以清晰、直观的方式展示给用户,允许用户通过点击目录条目进行导航。</span><h3>2.1.2 第二章 第一节 第二段</h3><span>组件需要能够自动提取网页内容中的所有标题元素(如 h1, h2, h3 等)。</span><span>提取的标题需要按照其在网页中的层级关系(如 h1 后面跟着的 h2 是其子章节)进行组织,形成一个目录容器。</span><span>目录容器需以清晰、直观的方式展示给用户,允许用户通过点击目录条目进行导航。</span></div></div>
</body>
<script src="./neat_directory.js"></script>
<script>let para = {"contentContainer":document.getElementById('divContent'),}let directory = new Directory(document.getElementById('divDirectory'),para);</script></html>
相关文章:
突破编程_前端_JS编程实例(目录导航)
1 开发目标 目录导航组件旨在提供一个滚动目录导航功能,使得用户可以方便地通过点击目录条目快速定位到对应的内容标题位置,同时也能够随着滚动条的移动动态显示当前位置在目录中的位置: 2 详细需求 2.1 标题提取与目录生成 组件需要能够自…...
扩展学习|系统理解数字经济
文献来源:[1]肖静华,胡杨颂,吴瑶.成长品:数据驱动的企业与用户互动创新案例研究[J].管理世界,2020,36(03):183-205.DOI:10.19744/j.cnki.11-1235/f.2020.0041. [2]陈晓红,李杨扬,宋丽洁等.数字经济理论体系与研究展望[J].管理世界,2022,38(02):208-22413…...
前端学习之列表标签
目录 有序列表 结果 无序标签 结果 数据标签 结果 有序列表 (注:注释是解释) <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title> </…...
华为OD面试分享14(2024年)
双非本,机试400分,部门流程与IT,base西安 分享面经攒人品 10.27 一面 深挖项目,面试官很友好,根据项目的每个技术点和场景来提问,比如项目中数据库数据量级有多大,什么时候会出现缓慢,如何解决的,有没有经过压力测试,经过优化后性能怎么样,项目中用到的Kafka和redis…...
安全测试报告-模板内容
1. 概述 为检验XXXX平台 系统的安全性,于 XXXX年 XX 月 XX 日至 XXXX年 XX 月 XX日对目标系统进行了安全测试。在此期间测试人员将使用各 种非破坏性质的攻击手段,对目标系统做深入的探测分析,进而挖掘系统中的安 全漏洞和风险隐患。研发团队…...
FreeRTOS学习笔记-基于stm32(3)中断管理
一、什么是中断 通俗点讲就是让CPU停止当前在做的事,转而去做更紧急的事。 二、中断优先级分组 这个紧急的事也有一个等级之分,优先级越高越先执行。stm32使用中断优先配置寄存器的高4位,共16级的中断优先等级。 stm32的中断优先等级可以分为…...
android pdf框架-6,文本生成pdf
前文介绍如何使用图片生成pdf,这里介绍如何使用文本生成pdf 使用mupdf生成 mupdf生成的pdf略大,字体可以自定义. 生成的代码不复杂,也有好几种,以story的方式生成为例 fun createPdfFromText(sourcePath: String, destPath: String): Boolean {val text EncodingDetect.rea…...
关于springboot一个接口请求后,主动取消后,后端是否还在跑
1、最近在思考一个问题,如果一个springboot的请求的接口比较耗时,中途中断该请求后,则后端服务是否会终止该线程的处理,于是写了一个demo RequestMapping(value "/test", method RequestMethod.GET)public BasicResul…...
理解自相关图AC和偏自相关图PAC Plots
when we talk about the time-series data, many factors affect the time series, but the only thing that affects the lagged version of the variable is the time series data itself. by Yugesh Verma 时序数据按照时间点的先后顺序进行排列,变化是在邻近的时间段之间发…...
.NetCore6.0实现ActionFilter过滤器记录接口请求日志
文章目录 目的实现案例:一.首先我们新建一个WebApi项目二.配置 appsettings.json 文件,配置日志存放路径三.创建 Model 文件夹,创建AppConfig类和ErrorLog类1.在AppConfig类中编写一个GetConfigInfo方法获取配置文件中的值2.在ErrorLog类中&a…...
代码详解:2024美团春招实习笔试第一场0309,是难还是简单?
前言: 1.第一题(模拟) 2.第二题(模拟) 3.第三题(二维前缀和) 4.第四题的思维(双指针) 5.第五题难度比较大(并查集删边离散化) 一.小美的MT MT 是美团的…...
平衡二叉树
前言 在关键字排列随机的情况下,二叉排序树的平均查找长度和 l o g n log n logn是等数量级的。在某些情况下,尚需在构成二叉排序树的过程中进行“平衡化”处理,使其成为平衡二叉树。 如果任何初始化序列构成的二叉排序树都是平衡二叉树&…...
脚本自动化 设置快捷方式并设置为管理员运行
自动化创建快捷方式并设置为始终以管理员权限运行,可以通过编写批处理脚本来实现。以下是一个创建.bat批处理文件快捷方式并设置为管理员运行的示例脚本: batch echo off set SCRIPT_PATH"C:\Scripts\myScript.bat" set SHORTCUT_PATH"%…...
TypeScript学习笔记(上):TypeScript的介绍、安装及常用类型
我对TypeScript的理解就是,TypeScript是增加了类型校验的JavaScript,能够把运行期错误提升至编译期 目录 TypeScript是什么? 安装编译 TS 的工具包 运行 TS 的步骤 TypeScript 常用类型 JS 已有类型 TS 新增类型 简单数据类型 数组类…...
Vue3学习记录(六)--- 组合式API之依赖注入和异步组件
一、依赖注入 1、简介 在前面的笔记中,我们学习过父组件向子组件传递数据时,需要借助props来实现。但如果父组件想要向孙子组件传递数据,那就要连续使用两层props逐级向下传递,如果要接收数据的是更深层的后代组件࿰…...
JZ76 删除链表中重复的结点
/*public class ListNode {int val;ListNode next null;ListNode(int val) {this.val val;} } */import java.util.*; public class Solution {public ListNode deleteDuplication(ListNode pHead) {//初步想想法: 弄一个hashmap 然后进行key存储起来。然后 如果存…...
20.2 nginx
20.2 nginx 1. 学习目标2. 介绍2.1 正向代理2.2 反向代理2.3 动态静态资源分离2.4 nginx优缺点3. 安装3.1 Linux安装****************************************************************************************************************************************************…...
MySQL学习Day26——事务基础知识
一、数据库事务概述: 事务是数据库区别于文件系统的重要特性之一,事务会让数据始终保持一致性,能通过事务机制恢复到某个时间点,可以保证提交到数据库的修改不会因为系统崩溃而丢失 1.查看引擎支持事务的情况:只有InnoDB存储引擎支持事务 SHOW ENGINES; 2.基本概念: 事…...
three.js 射线Ray,三维空间中绘制线框
效果: 代码: <template><div><el-container><el-main><div class"box-card-left"><div id"threejs"></div> <div>{{ res1 }}</div> <div>{{ res2 }}</div><…...
【Demo】游戏小地图
简介 该Demo基于2D关卡随机生成项目进行实现,旨在初步探索游戏小地图的制作。 演示 MiniMapDemo 资源下载 百度网盘(提取码:1314) 如果这篇文章对你有帮助,请给作者点个赞吧!...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
