看到一款树形结构,比较喜欢它的样式,就参照它的外观自己做了一个,练习一下CSS。

做出来的效果如下:

li { position: relative; padding: 5px 0; margin:0; }
#tree-div.tree>ul { padding: 0; margin: 0 }
.tree>ul ul>li::after { content: " "; position: absolute; top: 20px; left: -45px; width: 45px; border: none; border-top: 1px solid #ddd }
.tree ul>li:not(:last-child)::before { content: " "; position: absolute; top: 0; left: -45px; height: 100%; border: none; border-left: 1px solid #ddd }
.tree ul>li:last-child::before { content: " "; position: absolute; top: 0; left: -45px; height: 20px; border: none; border-left: 1px solid #ddd }
.tree span:hover,.tree span:hover+ul span { color: #fff; background-color: orange }
.tree span:hover,.tree span:hover+ul span,.tree span:hover+ul li::before,.tree span:hover+ul li::after { border-color: orange }
.tree .fa::before { margin-right: 5px }
.tree .fa-minus-circle,.tree .fa-plus-circle { cursor: pointer }
-->

  • 拉莫小学

    • 一年级

      • 一班
      • 二班
    • 二年级
    • 三年级
      • 一班
      • 二班
      • 三班

树的dom结构:

<div class="tree">
<ul>
<li>
<span><i class="fa fa-minus-circle"></i>拉莫小学</span>
<ul>
<li>
<span><i class="fa fa-minus-circle"></i>一年级</span>
<ul>
<li><span>一班</span></li><li><span>二班</span></li>
</ul>
</li>
<li>
<span>二年级</span>
</li>
<li>
<span><i class="fa fa-minus-circle"></i>三年级</span>
<ul>
<li><span>一班</span></li>
<li><span>二班</span></li>
<li><span>三班</span></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>

CSS代码:

/** tree.css zyj 2018.4.21 */
ul,li{list-style-type:none;}
.tree{display:block;position:relative;padding:5px 15px;}
.tree span{display:inline-block;box-sizing:border-box;height:30px;line-height:28px;min-width:60px;text-align:center;color:#888;border:1px solid #ddd;border-radius:5px;padding:0 8px;}
.tree ul{position:relative;padding-left:60px;margin:;}
.tree ul>li{position:relative;padding:5px 0;}
.tree>ul{padding:;margin:;}
/** 水平方向连线 */
.tree>ul ul>li:after{content:' ';position:absolute;top:20px;left:-45px;width:45px;border:none;border-top:1px solid #ddd;}
/** 垂直方向连线 */
.tree ul>li:not(:last-child):before{content:' ';position:absolute;top:;left:-45px;height:100%;border:none;border-left:1px solid #ddd;}
.tree ul>li:last-child:before{content:' ';position:absolute;top:;left:-45px;height:20px;border:none;border-left:1px solid #ddd;}
/** 控制鼠标移上去的颜色 */
.tree span:hover, .tree span:hover+ul span{color:#fff;background-color:orange;}
.tree span:hover, .tree span:hover+ul span, .tree span:hover+ul li:before, .tree span:hover+ul li:after{border-color:orange;}
/** 折叠图标 */
.tree .fa:before{margin-right:5px;}
.tree .fa-minus-circle, .tree .fa-plus-circle{cursor:pointer;}

里面引的fontawesome图标没法加载进来,导致折叠按钮显示不出,下面是原始树状图的截图:

数据是我用JS加载的,写了个加载数据的tree.js文件,源码如下:

/** tree.js zyj 2018.4.22 */
(function(name){
var tree, outer, defaultDateFormat; outer = {
setData : setData,
}; defaultDateFormat = {
unfold : true,
name : 'name',
childName : 'children'
}; function getDataFormat(dataFormat){
var index;
if(!dataFormat){
return defaultDateFormat;
}
for(index in defaultDateFormat){
dataFormat[index] = typeof dataFormat[index] == 'undefined'? defaultDateFormat[index] : dataFormat[index];
}
return dataFormat
} function initTreeJs(name){
var tree;
if(checkTreeNameUsed(name)){return;}
window[name] = outer;
initFoldIcon($('.tree'));
} function checkTreeNameUsed(name){
if(window[name]){
console.error("The window object name [" + name + "] has been used, tree.js can't be loaded! You can try another name." );
return true;
}
return false;
} function initFoldIcon(target){
target.off('click', 'span>i.fa').on('click', 'span>i.fa', function(e){
var ele = $(e.target);
if(ele.hasClass('fa-minus-circle')){
ele.removeClass('fa-minus-circle').addClass('fa-plus-circle').parent().next('ul').hide(200);
}else if(ele.hasClass('fa-plus-circle')){
ele.removeClass('fa-plus-circle').addClass('fa-minus-circle').parent().next('ul').show(200);
}
})
} function getJqueryObjectBySelector(selector){
var ele = $(selector);
if(typeof selector != 'string'){
console.error("The first parameter jquery selector [" + selector + "] must be a string!" );
return;
}
if(!ele.hasClass('tree')){
ele = ele.find('.tree');
}
if(ele.length != 1){
console.error("The selector [" + selector + "] expect only one element!" );
return;
}
return ele;
} function setData(selector, data, dataFormat){
var ele = getJqueryObjectBySelector(selector);
if(!ele){return;}
if(!data){return;}
if(!data.length){
data = [data];
}
dataFormat = getDataFormat(dataFormat);
dataFormat.topElement = true;
ele.empty().append(getTreeList(data, dataFormat));
initFoldIcon(ele);
} function getTreeList(data, dataFormat){
var i, single, name, children, childDataFormat,
array = [];
childDataFormat = dataFormat.child || dataFormat;
if(dataFormat.unfold){
array.push('<ul>');
}else if(dataFormat.topElement){
dataFormat.topElement = false;
array.push('<ul>');
}else{
array.push('<ul style="display:none;">');
}
for(i=0; i<data.length; i++){
single = data[i];
if(typeof dataFormat.name == 'function'){
name = dataFormat.name(single);
}else if(typeof dataFormat.name == 'string'){
name = single[dataFormat.name];
}else{
name = single['name'];
}
if(typeof dataFormat.childName == 'string'){
children = single[dataFormat.childName];
}else{
children = single['children'];
}
array.push('<li>');
array.push('<span>');
if(children && children.length > 0){
if(dataFormat.unfold){
array.push('<i class="fa fa-minus-circle"></i>');
}else{
array.push('<i class="fa fa-plus-circle"></i>');
}
array.push(name);
array.push('</span>');
array.push(getTreeList(children, childDataFormat));
}else{
array.push(name);
array.push('</span>');
}
array.push('</li>');
}
array.push('</ul>');
return array.join('');
} initTreeJs(name);
}('tree'))

偷懒没写注释,tree.js中目前只写了一个对外的接口 tree.setData(selector, data, dataFormat) 。参数selector是jQuery选择器,data是数据,dataFormat是数据格式。

比如加载上图的数据:

var dataTest = {
name:'拉莫小学',
children:[
{
name:'一年级',
children:[
{name:'一班'},
{name:'二班'}
]
},
{
name:'二年级'
},
{
name:'三年级',
children:[
{name:'一班'},
{name:'二班'},
{name:'三班'}
]
}
]
}; tree.setData('.tree', dataTest);

由于后台加载的数据不一定是按照{name:'*', children:[{name:'*'},...]}这种结构,所以留了dataFormat参数,自己去定义数据格式。

简单举个例子,假如后台数据格式是

var data =
{
id : '1',
title : '百度',
url : 'http://www.baidu.com',
subWeb :
[
{
id : '2',
title : '百度新闻',
url : 'http://news.baidu.com'
},
{
id : '3',
title : '百度知道',
url : 'http://zhidao.baidu.com'
},
{
id : '4',
title : '百度图片',
url : 'http://image.baidu.com'
},
]
}

那么dataFormat可以定义为

var dataFormat =
{
name : function(data){
return '<a href="' + data.url + '">' + data.title + '</a>';
},
childName : 'subWeb'
}

至于效果,读者自己去试咯。

CSS实现树形结构 + js加载数据的更多相关文章

  1. css 动态导入css文件 @import 动态js加载 都是静态的

    @import "http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.css" /*-防止各大cdn公共库加载地址失效 ...

  2. iScroll.js 向上滑动异步加载数据回弹问题

    iScroll是一款用于移动设备web开发的一款插件.像缩放.下拉刷新.滑动切换等移动应用上常见的一些效果都可以轻松实现. 现在最新版本是5.X,官网这里:http://iscrolljs.com/ ...

  3. js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符

    js中对arry数组的各种操作小结   最近工作比较轻松,于是就花时间从头到尾的对js进行了详细的学习和复习,在看书的过程中,发现自己平时在做项目的过程中有很多地方想得不过全面,写的不够合理,所以说啊 ...

  4. 关于使用Iscroll.js异步加载数据后不能滑动到最底端的问题解决方案

    关于使用Iscroll.js异步加载数据后不能滑动到最底端,拉到最下边又弹回去的问题困扰了我老半天,相信很多朋友都遇到了.我刚好不小心解决了,和大家分享一下.由于各种忙,下边就直接上代码吧. (前提是 ...

  5. 定时器详解和应用、js加载阻塞、css加载阻塞

    1.setTimeout().setInterval()详解和应用 1.1 详解: setTimeout.setInterval执行时机 1.2 存在问题: setInterval重复定时器可能存在的 ...

  6. FusionCharts简单教程(二)-----使用js加载图像和setDataXML()加载数据

          前面一篇对FusionCharts进行了一个简单的介绍,而且建立了我们第一个图形,但是那个是在HTML中使用<OBJECT>和<EMBED>标记来加载图形的,但是这 ...

  7. [JS前端开发] js/jquery控制页面动态加载数据 滑动滚动条自动加载事件

    页面滚动动态加载数据,页面下拉自动加载内容 相信很多人都见过瀑布流图片布局,那些图片是动态加载出来的,效果很好,对服务器的压力相对来说也小了很多 有手机的相信都见过这样的效果:进入qq空间,向下拉动空 ...

  8. 使用js加载图像和setDataXML()加载数据

    使用js加载图像和setDataXML()加载数据 前面一篇对FusionCharts进行了一个简单的介绍,而且建立了我们第一个图形,但是那个是在HTML中使用<OBJECT>和<E ...

  9. 新手教程:不写JS,在MIP页中实现异步加载数据

    从需求谈起:在 MIP 页中异步加载数据 MIP(移动网页加速器) 的 加速原理 除了靠谱的 MIP-Cache CDN 加速外,最值得一提的就是组件系统.所有 JS 交互都需要使用 MIP 组件实现 ...

随机推荐

  1. Spring集成ElasticSearch搜索引擎

    目录 前期安装 Maven支持库安装 添加log4j的配置文件 创建Client客户端 实现增删改查以及符合查询 实现查询数据 实现添加数据 实现删除数据 实现修改数据 实现复合查询数据 Elasti ...

  2. mssql sqlerver 脚本 计算数据表的结余数的方法分享

    转自:http://www.maomao365.com/?p=5710 摘要:今天接到一个需求,有一张数据表,记录的是消费明细数据,现在需要做一个累计结余,记录每次的数据结余合计,下文将展示一种sql ...

  3. js获取地址栏中的数据

    window.location.href:设置或获取整个 URL 为字符串window.location.pathname:设置或获取对象指定的文件名或路径window.location.search ...

  4. web前端(3)—— html标签及web页面结构

    本节内容简单介绍下html都有哪些标签 还是百度首页,查看源代码看看: 我把源代码复制下来另存为html文件里: 注意:网页文件的后缀都是html或者htm 我这用的pycharm编辑器(Python ...

  5. NVM 安装 nodejs

    Windows 安装: 下载NVM 安装包:https://github.com/coreybutler/nvm-windows/releases 下载nvm-setup.zip文件后,解压后安装 安 ...

  6. 终极 Shell——ZSH

    Shell是Linux/Unix的一个外壳,你理解成衣服也行.它负责外界与Linux内核的交互,接收用户或其他应用程序的命令,然后把这些命令转化成内核能理解的语言,传给内核,内核是真正干活的,干完之后 ...

  7. 【2018.05.05 C与C++基础】C++中的自动废料收集:概念与问题引入

    在阅读C++语言的设计与演化一书时,作者多次提到希望能设计出一个自动废料收集,然而出于种种考虑,始终未将自动废料收集纳入标准讨论中,而是由Coder自己考虑是否在程序中实现废料收集. 当然了,许多Ja ...

  8. Unity琐碎(3) UGUI 图文混排解决方案和优化

    感觉使用Unity之后总能看到各种各样解决混排的方案,只能说明Unity不够体恤下情啊.这篇文章主要讲一下个人在使用过程中方案选择和优化过程,已做记录.顺便提下,开源很多意味着坑,还是要开实际需求. ...

  9. 本学期c#总结

     本学期我学习了C#编程认识到了什么是方法什么是关键字,和代码的作用.认识到了编程不仅仅是对一个程序的编程,也是对数据的编程.程序是由数据组成的.c#本身就是一种语言,C#适用于生成面向.net fr ...

  10. Java多线程 Socket使用

    点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...