前言

这是一篇个人练习 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. 【Spark】Day04-Spark Streaming:与离线批量比较、架构特点、入门案例、创建(队列、数据源)、转换(有状态、无状态)、输出方式、进阶(累加、转换为DF、缓存持久化)、实战(窗口统计)

    一.概述 1.离线和实时计算 离线:数据量大,数据不会变化,MapReduce 实时:数据量小,计算过程要短 2.批量和流式处理 批量:冷数据,数据量大,速度慢 流:在线.实时产生的数据(快速持续到达 ...

  2. Jgit的使用笔记

    原文:Jgit的使用笔记 - Stars-One的杂货小窝 之前整的一个系统,涉及到git代码的推送,是通过cmd命令去推送的,然后最近在产品验收的时候,测试部门随意填了个git仓库,然后导致仓库代码 ...

  3. 【JVM故障问题排查心得】「内存诊断系列」Docker容器经常被kill掉,k8s中该节点的pod也被驱赶,怎么分析?

    背景介绍 最近的docker容器经常被kill掉,k8s中该节点的pod也被驱赶. 我有一个在主机中运行的Docker容器(也有在同一主机中运行的其他容器).该Docker容器中的应用程序将会计算数据 ...

  4. docker 第一课

    centos安装docker yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo ...

  5. C#开发的资源文件程序(可国际化) - 开源研究系列文章

    上次将小软件的线程池描述了,也将插件程序描述了,这次就将里面的资源文件相关的内容进行下记录,这里能够让程序做成国际化的形式(即多语言程序),主要就是通过这个资源文件的方式进行的处理.下面将对这个资源文 ...

  6. python之路52 ORM查询、ORM事务、查询优化、常用字段及参数、ajax方法

    Q查询进阶操作 from django.db.models import Q q_obj = Q() # 1.产生q对象 q_obj.connector = 'or' # 默认多个条件的连接是and可 ...

  7. python进阶之路9文件的处理方法

    内容回顾 字典内置方法 1.类型转换 dict() 2.重要操作 get() d[key] = values 常用 pop() update() 键存在则修改键值对 键不存在则新增键值对 fromke ...

  8. python进阶之路7 数据类型的内置方法

    内容回顾 while 循环补充说明 1.死循环 2.while循环嵌套和全局标志位 for循环 1.for 变量名 in 待遍历数据 for循环体代码 2.for 也可以与break continue ...

  9. swift中cocoapods问题

    设置完Podfile后,pod install出现   终端   pod repo add master https://github.com/CocoaPods/Specs.git 出现如下提示   ...

  10. ionic+vue+capacitor系列笔记--常见报错以及解决

    1.Require statement not part of import statement.(@typescript-eslint/no-var-requires) 解决 .eslintrc.j ...