? 看到一款樹形結構,比較喜歡它的樣式,就參照它的外觀自己做了一個,練習一下CSS。
? 做出來的效果如下:
- 拉莫小學
- 一年級
- 一班
- 二班
- 二年級
- 三年級
- 一班
- 二班
- 三班
- 一年級
樹的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:0;} .tree ul>li{position:relative;padding:5px 0;} .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;}
里面引的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' }
至于效果,讀者自己去試咯。
?