02#Web 实战:实现树形控件
前言
这是一篇个人练习 Web 前端各种常见的控件、组件的实战系列文章。本篇文章将介绍个人通过 JQuery + 无序列表 + CSS 动画完成一个简易的树形控件。
最终实现的效果是:

这样结构比较复杂的嵌套再嵌套的 HTML 结构必须先写一个静态的观察,不可能一步到位,事情是逐渐发展的。遵循自顶向下、逐步求精、模块化三个原则。
静态实现
HTML
点击查看 HTML 代码
<ul class="category">
<li class="category-item" data-displayed="false">
<div class="category-tip">分类</div>
<ul class="sub-category">
<li class="sub-category-item">item 01</li>
<li class="sub-category-item">item 02</li>
<li class="sub-category-item">item 03</li>
</ul>
</li>
<li class="category-item" data-displayed="false">
<div class="category-tip">分类</div>
<ul class="sub-category">
<li class="sub-category-item">item 01</li>
<li class="sub-category-item">item 02</li>
</ul>
</li>
<li class="category-item" data-displayed="false">
<div class="category-tip">分类</div>
<ul class="sub-category">
<li class="sub-category-item">item 01</li>
</ul>
</li>
</ul>
基本的结构设计就是,在外层是无序列表 ul,每一项内容 li 下面嵌套 div 和 ul 标签。每一层数据展示是类名为category-tip的标签,如果标签下面还有可以展开的内容就有sub-cagetory的 ul。
CSS
点击查看 CSS 代码
.category-item {
cursor: pointer;
--li-height: 0;
}
.category-item-active {
animation: category-display 0.18s cubic-bezier(0.42, 0, 0.18, 0.98) 0s;
}
.sub-category {
display: none;
}
.sub-category-active {
display: block;
animation: category-show 0.6s ease-in-out 0s;
}
@keyframes category-show {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes category-display {
from {
height: 0;
}
to {
height: var(--li-height);
}
}
观察最开始的效果展示可知,category-item被点击时需要展开到其子节点sub-category的高度。子节点需要有一种渐变的效果,动画设置的时间要比category-item节点展开的时间长一点。
JQuery
点击查看 JQuery 代码
$(".category-item").on("click", function () {
let displayed = $(this)[0].dataset.displayed;
if (displayed === "false") {
$(this).css({
"--li-height": `${$(this).children(".sub-category").height()}px`
});
$(this).addClass("category-item-active");
$(this).children(".sub-category").addClass("sub-category-active");
$(this)[0].dataset.displayed = "true";
} else {
$(this).removeClass("category-item-active");
$(this).children(".sub-category").removeClass("sub-category-active");
$(this)[0].dataset.displayed = "false";
}
});
要实现列表展开和收缩,必须要知道当前节点是否已经展开?因此,就必须给节点标记一个布尔值以便于判断是否展开的状态,正好 HTML 标签支持data-xxx的属性,我们可以把这个布尔值直接放在每一个需要展开的标签中:
<li class="category-item" data-displayed="false">......</li>
当点击节点时,JQuery 需要判断data-displayed是否已经展开,如果展开就移除category-item-active以及sub-category-active的动画;如果没有展开就添加这两个动画,实现展开效果。
改进
category-item-active有一个重大问题,就是点击时节点有类似于重影的重合效果。经过多次调试发现,动画开始时,高度从 0px 开始,所以发生了重影效果。正确是高度从category-tip的高度开始,到category-tip和sub-category结束。
$(this).css({
"--tip-height": `${$(this).children(".category-tip").height()}px`,
"--li-height": `${$(this).children(".sub-category").height()}px`
});
@keyframes category-display {
from {
height: 0;
}
to {
height: calc(var(--li-height) + var(--tip-height));
}
}
动态实现
上面都还是静态实现,树形控件肯定是多层的,接下来我们将写一个渲染树形控件的函数,并且用到递归函数完成 HTML 的渲染。
通过上面静态案例可知,抽离其数据为 JS 数组:
点击查看数据
let treeOcxData = [
{
tip: "分类",
child: [{ tip: "设计作品" }, { tip: "技巧杂烩", child: [{ tip: "Web 前端" }] }]
},
{
tip: "导航",
child: [{ tip: "固钉" }, { tip: "回到顶部" }, { tip: "面包屑" }]
},
{
tip: "数据展示"
}
];
抽离出来之后数据还是挺复杂的,不要慌,万事开头难。首先写一个递归函数能不能实现遍历所有的数据。
递归遍历数据
function rendTreeOcx(data) {
for (let i = 0; i < data.length; i++) {
console.log(data[i].tip);
if (data[i].child) {
rendTreeOcx(data[i].child);
}
}
}

每一个数据都成功的遍历出来了,接下来就是渲染 HTML。
渲染树形控件函数
前面递归数组的递归函数能够全部依次打印出数组中每一条数据。在此基础之上,我们要添加 HTML 模板进去,完成树形控件的渲染工作。
点击查看 JS 代码
function rendTreeOcx(data, enableFold) {
let template = `<ul class="tree-ocx-ul">`;
if (enableFold) template = `<ul class="tree-ocx-ul tree-ocx-ul-enable-fold">`;
for (let i = 0; i < data.length; i++) {
if (data[i].child) {
template += `
<li class="tree-ocx-li tree-ocx-li-enable-fold" data-is-folded="false">
<div class="tree-ocx-tip">
${data[i].tip}
</div>
${rendTreeOcx(data[i].child, true)}
`;
} else {
template += `
<li class="tree-ocx-li">
<div class="tree-ocx-tip tree-ocx-tip-normal">${data[i].tip}</div>
`;
}
template += `</li>`;
}
template += `</ul>`;
return template;
}
如果还有子节点就在if ( data[i].child )体内执行递归函数,否则就完成这一层的 HTML。
GitHub 仓库
02#Web 实战:实现树形控件的更多相关文章
- BootstrapBlazor实战 Tree树形控件使用(2)
继续上篇实战BootstrapBlazor树型控件Tree内容, 本篇主要讲解整合Freesql orm快速制作数据库后台维护页面 demo演示的是Sqlite驱动,FreeSql支持多种数据库,My ...
- BootstrapBlazor实战-Tree树形控件使用(1)
实战BootstrapBlazor树型控件Tree的使用, 以及整合Freesql orm快速制作数据库后台维护页面 demo演示的是Sqlite驱动,FreeSql支持多种数据库,MySql/Sql ...
- Web 前端实战:JQ 实现树形控件
前言 这是一篇个人练习 Web 前端各种常见的控件.组件的实战系列文章.本篇文章将介绍个人通过 JQuery + 无序列表 + CSS 动画完成一个简易的树形控件. 最终实现的效果是: 这样结构比较复 ...
- Web应用程序开发,基于Ajax技术的JavaScript树形控件
感谢http://www.cnblogs.com/dgrew/p/3181769.html#undefined 在Web应用程序开发领域,基于Ajax技术的JavaScript树形控件已经被广泛使用, ...
- 基于Bootstrap的JQuery TreeView树形控件,数据支持json字符串、list集合(MVC5)<二>
上篇博客给大家介绍了基于Bootstrap的JQuery TreeView树形控件,数据支持json字符串.list集合(MVC5)<一>, 其中的两种方式都显得有些冗余.接着上篇博客继续 ...
- TreeView树形控件递归绑定数据库里的数据
TreeView树形控件递归绑定数据库里的数据. 第一种:性能不好 第一步:数据库中查出来的表,字段名分别为UNAME(显示名称),DID(关联数据),UTYPE(类型) 第二步:前台代码 <% ...
- SharePoint2010沙盒解决方案基础开发——关于TreeView树形控件读取列表数据(树形导航)的webpart开发及问题
转:http://blog.csdn.net/miragesky2049/article/details/7204882 SharePoint2010沙盒解决方案基础开发--关于TreeView树形控 ...
- js树形控件—zTree使用总结
0 zTree简介 树形控件的使用是应用开发过程中必不可少的.zTree 是一个依靠 jQuery 实现的多功能 “树插件”.优异的性能.灵活的配置.多种功能的组合是 zTree 最大优点. 0.0 ...
- 关于 DevExpress.XtraTreeList.TreeList 树形控件 的操作
作为一个C#程序员,在写程序时一直以来都使用的微软那一套控件,用起来特别爽,可是最近公司的一个项目用到了DevExpress框架,不用不知道,一用吓一跳,不得不承认这个框架确实很强大,效果也很炫,但是 ...
- js树形控件
js树形控件 ztree http://www.treejs.cn/
随机推荐
- 记录一次缓存引起的线上BUG
背景 有一个需求大概是这样的,为了提高推荐系统的性能,需要本来从A服务获取的帖子信息,改为从Redis里面重新读取 Redis里面没有存帖子的所有信息,只存储了推荐系统必要的字段 大概是这样的: 至于 ...
- 1.5.6 NN与2NN-hadoop-最全最完整的保姆级的java大数据学习资料
目录 1.5.6 NN与2NN 1.5.6.1 HDFS元数据管理机制 1.5.6.2 Fsimage与Edits文件解析 1.5.6.2.1 Fsimage文件内容 1.5.6.2.2 Edits文 ...
- JS执行机制及ES6
一.JS执行机制 JS语言有个特点是单线程,即同一时间只能做一件事.单线程就意味着,所有的任务需要排队,前一个任务结束,才会执行后一个任务,可能造成页面渲染不连贯. 为了解决这个问题,利用多核CPU的 ...
- JavaScript:操作符:正负号和自增自减及其隐式转换数据类型
正负号 正号即加号,负号即减号,运算结果同数学意义一样: 对非数字类型进行正负号运算,会隐式转换为数字,再进行运算: 一些特殊的非数字,转换情况同算术运算符: 自增自减 自增即为++,自减即为--. ...
- 【转载】EXCEL VBA 选取非连续的单元格区域——Areas集合
出处:http://www.360doc.com/content/21/1113/17/77710807_1004011085.shtml 前面我们讲的大多是**并操作单个的单元格,或者是连续的单元格 ...
- 来自一位十年.net研发老人的吐血整理:.Net技术栈-网址导航
业余时间为什么整理这个? 内容聚合:不用一个一个搜索,我们很快可以进入常用技术官网 提高效率:多看官方文档可以最快,最准确的掌握相关的技术资讯,不用被一些没理解透或者有偏差的技术分享所带偏. 很多有经 ...
- WebGoat-8.2.2靶场之不安全的反序列化漏洞
前言 序列化是将变量或对象转换成字符串的过程 反序列化就是把一个对象变成可以传输的字符串,目的就是为了方便传输 而反序列化漏洞就是,假设,我们写了一个class,这个class里面存有一些变量.当这个 ...
- pnpm配置
之前通过 nvm 来管理了 nodejs 版本,结果安装 pnpm 之后,安装全局依赖报错,如下: PS C:\Users\Administrator> pnpm i -g commitizen ...
- python之路49 模板层标签 自定义过滤器 模板继承、模型层准备、ORM部分操作
模板层之标签 {% if 条件1(可以自己写也可以是用传递过来的数据) %} <p>周三了 周三了</p> {% elif 条件2(可以自己写也可以用传递过来的数据) %} & ...
- Redis 数据结构-双向链表
Redis 数据结构-双向链表 最是人间留不住,朱颜辞镜花辞树. 1.简介 Redis 之所以快主要得益于它的数据结构.操作内存数据库.单线程和多路 I/O 复用模型,进一步窥探下它常见的五种基本数据 ...