前言

这是一篇个人练习 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-tipsub-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 仓库

GitHub 仓库地址

02#Web 实战:实现树形控件的更多相关文章

  1. BootstrapBlazor实战 Tree树形控件使用(2)

    继续上篇实战BootstrapBlazor树型控件Tree内容, 本篇主要讲解整合Freesql orm快速制作数据库后台维护页面 demo演示的是Sqlite驱动,FreeSql支持多种数据库,My ...

  2. BootstrapBlazor实战-Tree树形控件使用(1)

    实战BootstrapBlazor树型控件Tree的使用, 以及整合Freesql orm快速制作数据库后台维护页面 demo演示的是Sqlite驱动,FreeSql支持多种数据库,MySql/Sql ...

  3. Web 前端实战:JQ 实现树形控件

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

  4. Web应用程序开发,基于Ajax技术的JavaScript树形控件

    感谢http://www.cnblogs.com/dgrew/p/3181769.html#undefined 在Web应用程序开发领域,基于Ajax技术的JavaScript树形控件已经被广泛使用, ...

  5. 基于Bootstrap的JQuery TreeView树形控件,数据支持json字符串、list集合(MVC5)<二>

    上篇博客给大家介绍了基于Bootstrap的JQuery TreeView树形控件,数据支持json字符串.list集合(MVC5)<一>, 其中的两种方式都显得有些冗余.接着上篇博客继续 ...

  6. TreeView树形控件递归绑定数据库里的数据

    TreeView树形控件递归绑定数据库里的数据. 第一种:性能不好 第一步:数据库中查出来的表,字段名分别为UNAME(显示名称),DID(关联数据),UTYPE(类型) 第二步:前台代码 <% ...

  7. SharePoint2010沙盒解决方案基础开发——关于TreeView树形控件读取列表数据(树形导航)的webpart开发及问题

    转:http://blog.csdn.net/miragesky2049/article/details/7204882 SharePoint2010沙盒解决方案基础开发--关于TreeView树形控 ...

  8. js树形控件—zTree使用总结

    0 zTree简介 树形控件的使用是应用开发过程中必不可少的.zTree 是一个依靠 jQuery 实现的多功能 “树插件”.优异的性能.灵活的配置.多种功能的组合是 zTree 最大优点. 0.0 ...

  9. 关于 DevExpress.XtraTreeList.TreeList 树形控件 的操作

    作为一个C#程序员,在写程序时一直以来都使用的微软那一套控件,用起来特别爽,可是最近公司的一个项目用到了DevExpress框架,不用不知道,一用吓一跳,不得不承认这个框架确实很强大,效果也很炫,但是 ...

  10. js树形控件

    js树形控件 ztree http://www.treejs.cn/

随机推荐

  1. Ubuntu 22.04 搭建K8s集群

    目录 1. 虚拟机基础配置 配置静态ip 设置主机名 设置hosts 安装ssh 2. Ubuntu系统设置 禁用swap 修改内核参数 3. 安装containerd 4. 安装Kubernetes ...

  2. Flask初步认识

    1.Flask基本认识 Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展包(数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现.比如可以用 Flask 扩展加入ORM. ...

  3. NC14501 大吉大利,晚上吃鸡!

    题目链接 题目 题目描述 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏. 在游戏中,皮皮和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的 ...

  4. 探究SQL SERVER 更改跟踪

    1.介绍 SQL SERVER在2008以上的版本提供两个用于数据库中跟踪数据更改的功能:变更数据捕获(CDC)与更改跟踪(CT).这两个功能使应用程序能够确定对数据库中的用户表所做的 DML 更改( ...

  5. js取不到iframe元素

    跨域 iframe 请绕道,下文是针对非跨域 iframe 的问题排除 1.iframe 取不到值的问题的原因 1. 父页面未加载完成 2. iframe 未加载完成 3. 语法使用错误 4. 跨域( ...

  6. python进阶之路14 之函数内置方法、可迭代对象、异常捕获处理

    重要内置函数 1.map() 映射 l1 = [1, 2, 3, 4, 5] # def func(a): # return a+1 res = map(lambda x:x+1, l1) print ...

  7. [WPF]限制程序单例运行

    代码 System.Threading.Mutex mutex; protected override void OnStartup(StartupEventArgs e) { bool ret; m ...

  8. ABC238E Range Sums

    简要题意 有一个长度为 \(N\) 的序列 \(a\),你知道 \(Q\) 个区间的和.求是否可以知道 \([1,n]\) 的和. \(1 \leq N,Q \leq 2 \times 10^5\) ...

  9. Linux c 检测U盘挂载路径方法

    思路: 1.使用df -h |grep mnt shell 命令查找到挂载路径信息 本代码是将结果存入文件中,再从文件中解析出路径信息.也可使用fopen直接从管道中读取信息 2.解析出信息最后的/m ...

  10. Python 跨模块使用全局变量(自定义类型)

    gol.py def _init():#初始化 global _global_dict _global_dict = {} def set_value(key,value): "" ...