突破编程_前端_JS编程实例(简单树结构组件)

1 开发目标

实现如下简单树结构组件:

在这里插入图片描述

再点击树节点后,会调用客户端传入的回调函数:

在这里插入图片描述

2 详细需求

简单树结构组件需根据客户端提供的参数创建,具备动态构建树形结构节点、选项卡切换及自定义内容显示等功能:

(1)树形结构组件的创建与初始化: 类似于 echarts 等知名商业组件的创建与初始化方式,本组件需要根据客户端提供的参数 container 以及 para 进行创建和初始化。
container 是一个已存在的 DOM 元素(一般是 DIV),组件将在此元素内部构建 TAB 区域,包含选项卡以及 TAB 面板。
para 是本组件的配置参数,该对象应包含以下属性:

{"nodes":[{"id":"1","name":"node_1","children":[{"id":"11","name":"node_1_1",},{"id":"12","name":"node_1_2","children":[{"id":"121","name":"node_1_2_1",},{"id":"122","name":"node_1_2_2",},]},]},{"id":"2","name":"node_2",},],"onClickTreeNode":callback_function,
}

(2)树形结构渲染: 组件应能正确渲染树形结构,每个节点应清晰展示。

(3)节点单选: 用户点击树形结构中的某个节点时,该节点应被选中,同时其他节点应取消选中状态。

(4)节点状态反馈: 选中的节点应有明显的视觉反馈,如变色或添加特殊标记。

(5)事件监听: 应提供事件监听机制,允许用户监听节点的选中事件,以便在节点被选中时执行特定操作。

3 代码实现

首先创建一个 neat_treewidget.js 文件,该文件用于本组件的工具类、窗体部件基类以及各个实现类的代码构建。

在具体的业务代码编写之前,先实现一个工具类以及一些工具方法,方便后面调用:

class CommonUtil {// 设置 DIV 中的文字为水平与垂直居中static centerTextInDiv(container) {container.style.display = 'flex';container.style.textAlign = 'center';container.style.justifyContent = 'center';container.style.flexDirection = 'column';}
}

该工具类中包含一个可以将 DIV 中的文字设置为水平与垂直居中的静态方法。

接下来,定义一个通用的显示窗体的基类:

class NeatBaseWid {constructor(container, para) {this.container = container;	// 接收调用者传入的 DOM 元素(一般是 DIV)this.para = para;	// 保存调用者传入的 para 对象}
}

然后开始定义树节点类型:

class NeatTreeNode extends NeatBaseWid {static LEVEL_OFFSET = 10;     // 每个级别的树节点偏移像素static NODE_HEIGHT = '23px';     // 树节点高度static NODE_NAME_FONTSIZE = '14px';     // 默认标题字符串的字体大小static NODE_NAME_COLOR = '#000';     // 默认标题字符串字体颜色static NODE_OPENCLOSE_ICON_WIDTH = '23px';     // 树节点打开、关闭小箭头图标的宽度static NODE_OPENCLOSE_ICON_CLASS_OPEN = 'fa fa-angle-down';			//打开static NODE_OPENCLOSE_ICON_CLASS_CLOSE = 'fa fa-angle-right';		//关闭constructor(container, para) {super(container, para);this.id=this.para.id;this.name=this.para.name;this.parent = para.treeNode ?? null;        // 父节点this.level = (para.treeNode && (para.treeNode.level + 1)) ?? 0;   // 节点的级别,最高一级是根节点this.nameContainer = null; // 树节点的标题容器this.openCloseIconContainer = null; // 树节点的打开、关闭小箭头图标容器this.children = [];       // 子节点this.childrenContainer = null; // 子节点容器this.render();}

上面代码定义了 NeatTreeNode 的一些默认属性与成员变量,并且创建构造函数,该函数接收调用者传入的 DIV 容器,并且调用 render 方法。
在 render 方法,需要渲染当前树节点,并且还要根据是否有子节点的情况,创建子节点容器:

	render() {this.container.innerHTML = '';  // 清空容器// 渲染当前树节点let nodeContainer = document.createElement('div');nodeContainer.style.display = 'flex';nodeContainer.style.width = '100%';nodeContainer.style.height = NeatTreeNode.NODE_HEIGHT;this.container.appendChild(nodeContainer);

上面代码创建了当前树节点的容器,接下来需要根据当前节点的级别,做一个偏移处理:

		// 如果当前树节点的级别大于 0,则放一个偏移容器if (this.level > 0) {let offsetContainer = document.createElement('div');offsetContainer.style.width = this.level*NeatTreeNode.LEVEL_OFFSET + 'px';nodeContainer.appendChild(offsetContainer);}

接下来,如果当前树节点有子节点,则显示树节点的打开、关闭小箭头图标,如果没有子节点,则做一个简单的偏移处理即可:

		// 如果当前树节点有子节点,则显示树节点的打开、关闭小箭头图标if (this.para.children && this.para.children.length > 0) {this.openCloseIconContainer = document.createElement('i');this.openCloseIconContainer.className = NeatTreeNode.NODE_OPENCLOSE_ICON_CLASS_OPEN;this.openCloseIconContainer.style.width = NeatTreeNode.NODE_OPENCLOSE_ICON_WIDTH;this.openCloseIconContainer.style.height = '100%';CommonUtil.centerTextInDiv(this.openCloseIconContainer);nodeContainer.appendChild(this.openCloseIconContainer);// 树节点打开或关闭let that = this;this.openCloseIconContainer.onclick = function () {if(NeatTreeNode.NODE_OPENCLOSE_ICON_CLASS_OPEN === that.openCloseIconContainer.className){that.openCloseIconContainer.className = NeatTreeNode.NODE_OPENCLOSE_ICON_CLASS_CLOSE;that.childrenContainer.style.display='none';}else{that.openCloseIconContainer.className = NeatTreeNode.NODE_OPENCLOSE_ICON_CLASS_OPEN;that.childrenContainer.style.display='block';}}} else {let offsetContainer = document.createElement('div');offsetContainer.style.width = NeatTreeNode.NODE_OPENCLOSE_ICON_WIDTH;nodeContainer.appendChild(offsetContainer);}

注意:上面代码中,在创建打开、关闭小箭头图标后,还定义了点击事件的处理函数。
然后,创建当前的树节点标题,并且定义点击树节点标题时的事件处理函数:

        // 树节点标题this.nameContainer = document.createElement('div');this.nameContainer.style.flexGrow = '1';this.nameContainer.innerText = this.para.name;CommonUtil.centerTextInDiv(this.nameContainer);this.nameContainer.style.textAlign = 'left';this.nameContainer.style.cursor = 'pointer';nodeContainer.appendChild(this.nameContainer);// 点击树节点的触发动作let that = this;this.nameContainer.onclick = function () {that.para.onClickTreeNode(that);}

最后,根据是否有子节点的情况,创建子节点容器:

        // 创建子树节点if(this.para.children && this.para.children.length > 0){this.childrenContainer = document.createElement('div');this.childrenContainer.style.width = '100%';this.container.appendChild(this.childrenContainer);this.para.children.forEach(element => {let nodeContainer = document.createElement('div');this.childrenContainer.appendChild(nodeContainer);element.treeNode = this;element.onClickTreeNode = this.para.onClickTreeNode;let treeNode = new NeatTreeNode(nodeContainer, element);this.children.push(treeNode);});}}

至此,完成了整个渲染函数 render 的构建。

下一步,创建树结构类型:

class NeatHeaderTreeWidget extends NeatBaseWid {constructor(container, para) {super(container, para);this.rootTreeNodes = [];      // 根节点集合this.render();}render() {// 清空容器this.container.innerHTML = '';// 渲染树结构this.container.style.width = '100%';this.container.style.height = '100%';// 创建树节点this.para.nodes.forEach(element => {let nodeContainer = document.createElement('div');this.container.appendChild(nodeContainer);element.onClickTreeNode = this.para.onClickTreeNode;let treeNode = new NeatTreeNode(nodeContainer, element);this.rootTreeNodes.push(treeNode);});}
}

注意:创建树结构类型的渲染函数 render 中的创建树节点实际是创建根节点,至于子节点则通过根节点的渲染函数创建(是一个递归创建的过程)。

完成树结构组件的代码编写后,可以创建 neater_treewidget.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><link rel="stylesheet" href="./font-awesome-4.7.0/css/font-awesome.css">
</head><body><div id="divMain" style="height: 100%;width: 100%;"></div>
</body>
<script src="./neat_treewidget.js"></script>
<script>let para = {"nodes": [{"id": "1","name": "根节点 node_1","children": [{"id": "11","name": "一级子节点 node_1_1",},{"id": "12","name": "一级子节点 node_1_2","children": [{"id": "121","name": "二级子节点 node_1_2_1",},{"id": "122","name": "二级子节点 node_1_2_2",},]},]},{"id": "2","name": "根节点 node_2",},{"id": "3","name": "根节点 node_3","children": [{"id": "31","name": "一级子节点 node_3_1",},]},{"id": "4","name": "根节点 node_4",},],"onClickTreeNode":clickTreeNode,};function clickTreeNode(treeNode){alert(treeNode.name);}let treeWidget = new NeatHeaderTreeWidget(document.getElementById('divMain'), para);</script></html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/511178.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL——性能调优

性能调优&#xff08;重要&#xff09; SQL 优化的目的 减少磁盘 IO&#xff1a;尽可能避免全表扫描、尽量使用索引、尽量使用覆盖索引减少回表操作减少 CPU 和内存的消耗&#xff0c;尽可能减少排序、分组、去重之类的操作&#xff0c;尽量减少事务持有锁的时间 优化途径&…

C++:String的模拟实现

模拟实现的节奏比较快&#xff0c;大家可以先去看看博主的关于string的使用&#xff0c;然后再来看这里的模拟实现过程 C&#xff1a;String类的使用-CSDN博客 String模拟实现大致框架迭代器以及迭代器的获取&#xff08;public定义&#xff0c;要有可读可写的也要有可读不可写…

Day16:信息打点-语言框架开发组件FastJsonShiroLog4jSpringBoot等

目录 前置知识 指纹识别-本地工具-GotoScan&#xff08;CMSEEK&#xff09; Python-开发框架-Django&Flask PHP-开发框架-ThinkPHP&Laravel&Yii Java-框架组件-Fastjson&Shiro&Solr&Spring 思维导图 章节知识点 Web&#xff1a;语言/CMS/中间件/…

基于springboot+vue的医疗挂号管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

002-CSS-三角形

三角形 普通三角形带阴影的三角形&#xff1a;box-shadow带阴影的三角形&#xff1a;filter 普通三角形 &#x1f4a1; Tips&#xff1a;设置 div 盒子宽高为零&#xff0c;使用单边框实现 .triangle {width: 0;height: 0;border: 20px solid transparent;border-top-color: …

GitLab EE 企业版破解

在当今数字化时代&#xff0c;软件开发与团队协作已经成为现代企业不可或缺的一部分。而在这个过程中&#xff0c;版本控制、协作和持续集成等工具的运用变得至关重要。GitLab作为一个领先的、完整的DevOps平台&#xff0c;为团队提供了一个集成的解决方案&#xff0c;使得软件…

Thingsboard本地源码部署教程

本章将介绍ThingsBoard的本地环境搭建&#xff0c;以及源码的编译安装。本机环境&#xff1a;jdk11、maven 3.6.2、node v12.18.2、idea 2023.1、redis 6.2 环境安装 开发环境要求&#xff1a; Jdk 11 版本 &#xff1b;Postgresql 9 以上&#xff1b;Maven 3.6 以上&#xf…

前端+php:实现提示框(自动消失)

效果 php部分&#xff1a;只展示插入过程 <?php//插入注册表中$sql_insert "INSERT INTO regist_user(userid,password,phone,email)VALUES (" . $_POST[UserID] . "," . CryptPass($_POST[Password]) . "," . $_POST[Phone] . ",&qu…

论文阅读:2022Decoupled Knowledge Distillation解耦知识蒸馏

SOTA的蒸馏方法往往是基于feature蒸馏的&#xff0c;而基于logit蒸馏的研究被忽视了。为了找到一个新的切入点去分析并提高logit蒸馏&#xff0c;我们将传统的KD分成了两个部分&#xff1a;TCKD和NCKD。实验表明&#xff1a;TCKD在传递和样本难度有关的知识&#xff0c;同时NCK…

javascript作用域编译浅析

作用域思维导图 1&#xff1a;编译原理 分词/词法分析 如果词法单元生成器在判断a是一个独立的词法单元还是其他词法单元的一部分时&#xff0c;调用的是有状态的解析规则&#xff0c;那么这个过程就被称为词法分析。 解析/语法分析 由词法单元流转换成一个由元素逐级嵌套所组…

CVE-2024-23334 AIOHTTP 目录遍历漏洞复现

aiohttp简介 aiohttp 是一个基于 asyncio 实现的 Python HTTP 客户端和服务器框架。它提供了异步的 HTTP 客户端和服务器功能&#xff0c;能够处理高并发的网络请求。以下是关于 aiohttp 的一些重要特点和用途&#xff1a; 基于 asyncio&#xff1a;aiohttp 是基于 Python 的 a…

no declaration can be found for element ‘rabbit:connection-factory‘

spring-mvc 配置 rabbitmq 出现问题。 我的解决方案如下&#xff1a; 1 找到配置文件 spring-rabbitmq.xml 我的配置文件叫&#xff1a;spring-rabbitmq.xml&#xff0c;你们按照自己的查找。 2 定位如下URI 接着 Ctrl鼠标左键 3 确定spring-rabbit-x.x.xsd 按照步骤2 &…