突破编程_前端_JS编程实例(目录导航)

这篇具有很好参考价值的文章主要介绍了突破编程_前端_JS编程实例(目录导航)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 开发目标

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

目录导航滚动条,突破编程_前端_JS编程实例,前端,javascript,开发语言

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 文件,调用该组件:文章来源地址https://www.toymoban.com/news/detail-841742.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编程实例(目录导航)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 突破编程_前端_ACE编辑器(选中区域、跳转行以及点击事件)

    要在 ACE 编辑器中选中一个区域,通常需要使用编辑器的 selection 对象。 以下是一个简单的示例,展示了如何使用 ACE 编辑器的 API 来选中一个特定的区域: 初始化 ACE 编辑器:首先,需要在页面上初始化 ACE 编辑器(在“突破编程_前端_ACE编辑器(概述)”有具体说明)。 获

    2024年04月10日
    浏览(33)
  • Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较

    Flutter vs 前端 杂谈 SliverAppBar的弹性背景的显隐效果使用Html+JS怎么实现 作者 : 李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 : 291148484@163.com 本文地址 :https://blog.csdn.net/qq_28550263/article/details/134149018 在 Flutter 中,最简单的 appbar 就是 Appbar 组件,它没有任何难点,任何刚

    2024年02月05日
    浏览(36)
  • web前端框架Javascript之JavaScript 异步编程史

    早期的 Web 应用中,与后台进行交互时,需要进行 form 表单的提交,然后在页面刷新后给用户反馈结果。在页面刷新过程中,后台会重新返回一段 HTML 代码,这段 HTML 中的大部分内容与之前页面基本相同,这势必造成了流量的浪费,而且一来一回也延长了页面的响应时间,总

    2024年02月14日
    浏览(38)
  • 探索 JavaScript ES8 中的函数式编程并通过实例加以实践

    💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】 🤟 基于Web端打造的:👉轻量化工具创作平台 💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 函数式编程是一种强大的范式,强调使用纯函数和不可变数据。在本文中,我们将通过实际示例探讨如何

    2024年02月22日
    浏览(35)
  • 原生HTML+CSS+JS制作自己的导航主页(前端大作业,源码+步骤详解)

    链接:https://pan.baidu.com/s/1uaRCJXyIrY56NXabau4wjw?pwd=LDL6 提取码:LDL6 咕咕了好久啦,今天使用原生HTML+CSS+JS做一个很简单的个人定制的导航主页吧! 先看下完整的效果图吧! 接下来的文章将逐步带领大家制作,现在太晚了,就精简了下,删除了部分动画效果,项目整体非常简单!

    2024年01月22日
    浏览(34)
  • 前端学习记录~2023.8.10~JavaScript重难点实例精讲~第6章 Ajax

    本章是第六章Ajax相关的内容。 Ajax是一种流行的前后端数据交互的方式,通过异步请求就可以在不需要刷新页面的情况下,达到局部刷新的效果。 Ajax并非是一种全新的技术,而是由以下技术组合而成: 使用CSS和XHTML做页面呈现 使用DOM进行交互和动态显示 使用XMLHttpRequest对象

    2024年02月11日
    浏览(24)
  • 【剧前爆米花--前端三剑客】JavaScript(WebAPI)中的相关方法和实例

    作者:困了电视剧 专栏:《JavaEE初阶》 文章分布:这是一篇关于JavaScript(WebAPI)的文章,在这篇文章中我会简单介绍一些常用的js方法,并给出他们的应用实例,希望对你有所帮助!   目录 什么是WebAPI DOM的基本概念 什么是DOM DOM树 事件初识 基本概念 事件三要素 获取元素

    2024年02月16日
    浏览(27)
  • jQuery.js - 前端必备的Javascript库

    作者: WangMin 格言: 努力做好自己喜欢的每一件事 jQuery.js 是什么? jQuery是一个快速简洁、免费开源易用的JavaScript框架, 倡导写更少的代码,做更多的事情 。它封装JavaScript常用的功能代码,提供了一种简便的JavaScript设计模式,以及我们开发中常用到的操作DOM的API,优化HTML文

    2024年02月05日
    浏览(46)
  • 前端学习记录~2023.8.3~JavaScript重难点实例精讲~第5章 DOM与事件

    本章是第五章DOM与事件相关的内容。 DOM是文档对象模型,全称为Document Object Model。DOM用一个逻辑树来表示一个文档,树的每个分支终点都是一个节点,每个节点都包含着对象。DOM提供了对文档结构化的表述,通过绑定不同的事件可以改变文档的结构、样式和内容,从而能实现

    2024年02月12日
    浏览(34)
  • 快速认识,前端必学编程语言:JavaScript

    JavaScript是构建Web应用必学的一门编程语言,也是最受开发者欢迎的热门语言之一。所以,如果您还不知道JavaScript的用处、特点的话,赶紧补充一下这块基础知识。 JavaScript 是一种高级、单线程、垃圾收集、解释或即时编译、基于原型、多范式、动态语言,具有非阻塞事件循

    2024年02月05日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包