treeview控件如何绑定xml文件数据_前端组件之文件树

组件从零之文件树

很久没有更新了,今天就来谈谈文件树这个组件的一些原理和做法。首先看看文件树的组件效果,如下图就是一个很基本的文件树。

dc052352f373d2114f5acb513ec85699.png
效果图

原理

首先讲一下原理,其实也还是通过 display:block和display:none 的实现。在一个无序列表中,有的li标签下包裹着子树,而有的文件树下没有,那些有子树的文件我们前面给他一个加和减的符号用于辨识。 对于有子树的文件夹,默认情况下是加号的图标,子树通过display:none而隐藏。当点击对应的li时,把相应的子树通过 display:block显示出来即可。而对于子树的缩放,则可以直接用padding-left进行缩放就好了。假设缩放量一层为20px,那么只要对应小一级别就缩放20px对应倍数就好了。

html代码清单

<div>
    <ul>
        <li>
        <div  style="padding-left: 0px">
        <i class="icon icon-control icon-plus"></i>
        <i class="icon icon-file"></i>
        <span>全部文件</span>
        </li>
    </ul>
</div>

这个就是最基础的结构了。其中style中的padding-left直接控制缩放量。icon直接导入背景图片,通过改变雪碧图的background-position来 控制对应图标。当然假如有子级的话只要在li标签内的span标签后面继续嵌套即可。

下图是用到的图

50c2fe82d735ef077450a41f335ca026.png
用到的雪碧图

css代码清单

.icon {
   display: inline-block;
   background: url(../img/icon.png) no-repeat;
   vertical-align: middle;
 }
 .icon-minus {
   width: 15px;
   height: 15px;
   margin: 0 4px;
   background-position: -30px -22px;
 }
 .icon-plus {
   width: 15px;
   height: 15px;
   margin: 0 4px;
   background-position: -30px 0;
 }
 .icon-file {
   width: 22px;
   height: 18px;
   margin-right: 5px;
   background-position: 0 -22px;
 }

假设已经有了下图这样的结果了,下一步就是通过js来控制点击行为。

dc052352f373d2114f5acb513ec85699.png

简单来说就是给有子代的li绑定事件监听,通过更改类名实现 display:block和display:none ,同时更换加减号图标。 通过这种方法,我们能实现方法,但是每次假如想添加子数,就只能通过臃长的代码来一步一步解决。 所以下面讲讲如何通过js(jq),来实现便捷一点的文件树。


通过JavaScript实现复杂一点的文件树

第一步首先是把用到的样式和结构完成好。

css代码清单

* { margin: 0; padding: 0; }

body{ 
    font-size: 14px; 
    color: #333; 
    font-family: "microsoft yahei";
}
 ul, li { list-style-type: none;}

 #treeView {
   width: 600px;
   margin: 20px auto 0;
   border: 1px solid #f2f2f2;
 }
 .treeNode {
   height: 32px;
   border: 1px solid #fff;
   border-width: 1px 0;
   cursor: pointer;
   font-size: 0;
 }
  .treeNode:hover {
   background: #f4f9fd;
   border-color: #e5f0fb;
 }
 .treeNode-cur,
 .treeNode-cur:hover {
   background: #e5f0fb;
   border-color: #BBD4EF #fff;
 }
 .icon {
   display: inline-block;
   background: url(../img/icon.png) no-repeat;
   vertical-align: middle;
 }
 .icon-minus {
   width: 15px;
   height: 15px;
   margin: 0 4px;
   background-position: -30px -22px;
 }
 .icon-plus {
   width: 15px;
   height: 15px;
   margin: 0 4px;
   background-position: -30px 0;
 }
 .icon-file {
   width: 22px;
   height: 18px;
   margin-right: 5px;
   background-position: 0 -22px;
 }
 .title {
   position: relative;
   top: 6px;
   font-size: 14px;
 }

 .treeNode-empty .icon-minus {
   background-position: -999px -999px;
 }
 .treeNode-empty .icon-plus {
   background-position: -999px -999px;
 }

  #treeView ul.none {
   display: none;
 }

结构上,我们只需要一行代码,因为后续的代码都是通过js渲染html结构。

html代码清单

<div id="treeView"></div>

第二步,新建一个js文件保存用到文件树数据

不同于用html上直接写结构,对于每一个数的节点,我们通过数组记录,每一个数组子项有三个属性, 分别是id,记录第几级的pid,还有这个子项的标题(文字)显示。

js代码清单

var data = {
        files: [
        {
            id: 0,
            pid: -1,
            title: '全部文件'
        },

        {
            id: 1,
            pid: 0,
            title: '我的图片'
        },
        {
            id: 2,
            pid: 0,
            title: '我的音乐'
        },
        {
            id: 3,
            pid: 0,
            title: '我的电影'
        },
        {
            id: 4,
            pid: 0,
            title: '我的书籍'
        },

        {
            id: 11,
            pid: 1,
            title: '风景'
        },
        {
            id: 12,
            pid: 1,
            title: '人物'
        },
        {
            id: 13,
            pid: 1,
            title: '动物'
        },

        {
            id: 41,
            pid: 4,
            title: 'JavaScript'
        },
        {
            id: 42,
            pid: 4,
            title: 'Java'
        },
        {
            id: 43,
            pid: 4,
            title: 'PHP'
        }
        ]
    };

对应的最外层就是全部文件的就是-1层,然后点开显示的就是第0层。对应的pid为1即pid为0的那一层里面第一个子树的子树。 (好像有点绕,其实看图可以看得出来!!)

所以你想添加,删除或者修改文件树,直接通过在这个文件中修改即可,而不是去到html文件中添加一大堆的代码。

第三步,获取刚才js中保存的数据。

这里我另外新建了一个文件用来保存和获取文件树的数据。

js代码清单

function getLevelById(data,id) {
        return getParents(data,id).length;
    }

    function hasChilds(data,id){
        return getChildById(data,id).length !== 0;
    }

    function getChildById(arr,pid){
        var newArr = [];
        for( var i = 0; i < arr.length; i++ ){
            if( arr[i].pid == pid ){
                newArr.push(arr[i]);
            }
        };

        return newArr;
    }

    function getParents(data,currentId){
        var arr = [];
        for( var i = 0; i < data.length; i++ ){
            if( data[i].id == currentId ){
                arr.push(data[i]);
                arr = arr.concat(getParents(data,data[i].pid))
                break;
            }
        }
        return arr;
    }

第四步,设置添加到html中的模板。

要设置html模板,我们首先就得要获取这个容器treeView和保存的数据,然后我们根据最简单实现的文件树中的一个节点为模板, 把可以修改的内容替换成保存的数据。还要获取对应的图标,当发生变化和默认时对应的样子。

第五步,对每个节点设置点击事件

这一步最主要就是获取节点和判断其有没有子树,有和无又是对应两个不同的处理。

下面是这两部最终的代码

js代码清单

function index(){
        var treeView = document.getElementById("treeView");
        var treeData=data.files;

        treeView.innerHTML = treeHtml(treeData, -1);                                            // 初始化

        var fileItem=document.getElementsByClassName("treeNode");
        var root_icon=fileItem[0].getElementsByClassName("icon").item(0);   //获取加号图标
        root_icon.className = 'icon icon-control icon-minus';                           //把图标换成减图标

        tools.each(fileItem, function (item) {                                                      //遍历每个子树节点
          filesHandle(item);                                                                                            //每个节点设置操作
        });

        function treeHtml(fileData, fileId){                                                            //html渲染
            var _html='';
            var children = getChildById(fileData, fileId);                                  //获取子树数组
            var hideChild = fileId > 0 ? 'none' : '';                                               //当id>0即非父树时隐藏所有子树

            _html += '<ul class="'+hideChild+'">';                                                  

            children.forEach(function (item, index) {                                               //遍历每个子代渲染html
                var hasChild = hasChilds(fileData, item.id);                                    //判断是否有子树
                var className = hasChild ? '' : 'treeNode-empty';                           //无子树则为空子树样式
                var treeRoot_cls = fileId === -1 ? 'treeNode-cur' : '';             //设置子树类名
                var level=getLevelById(fileData, item.id);                                      //获取子树在第几层级
                var distance=(level-1) * 20 +"px";                                                      //设置子树的缩放量

                // html模板内容添加
                 _html += `
                  <li>
                    <div class="treeNode ${className} ${treeRoot_cls}" style="padding-left: ${distance}" data-file-id="${item.id}">
                      <i class="icon icon-control icon-plus"></i>
                      <i class="icon icon-file"></i>
                      <span class="title">${item.title}</span>
                    </div>
                    ${treeHtml(fileData, item.id)}                          
                  </li>`;
            });

             _html += '</ul>';                                                                                          //嵌套ul标签

            return _html;
        }


        function filesHandle(item) {
          tools.addEvent(item, 'click', function () {                           //每个节点添加点击事件
            // var treeNode_cur=document.getElementsByClassName("treeNode-cur")[0];
            var treeNode_cur = tools.$('.treeNode-cur')[0];             //获取节点
            var fileId = item.dataset.fileId;                               //获取节点的id
            var curElem = document.querySelector('.treeNode[data-file-id="'+fileId+'"]');
            var hasChild = hasChilds(treeData, fileId);                     //是否有子数
            var icon_control = tools.$('.icon', item)[0];                   //符号
            var openStatus = true;                                                              //状态

            // treeNode_cur.classList.remove("treeNode-cur");               //移除样式类treeNode-cur
            // curElem.classList.add("treeNode-cur");                               //增加样式类treeNode-cur
            tools.removeClass(treeNode_cur, 'treeNode-cur');                
            tools.addClass(curElem, 'treeNode-cur');                        

            if (hasChild) {
              openStatus = tools.toggleClass(item.nextElementSibling, 'none');              //如果没有子代时treeNode下个节点ul设置为none样式
              if (openStatus) {                                                                                                             
                icon_control.className = 'icon icon-control icon-plus';                             //默认状态true显示的是加号符号
              } else {
                icon_control.className = 'icon icon-control icon-minus';                            //打开后状态已经是false了,这个时候显示减号
              }
            }

          });
        };
    }

23e558ac7bee20095fc9bafb2d5090e1.png

7dad23b68dcbb717614308ca8cb12fac.png

dc052352f373d2114f5acb513ec85699.png

以上代码就实现了文件树效果了。原理其实很容易,但是需求不同所以做的方式也不同。 希望能对你有帮助,这个系列也当做我自己个人学习的方式继续更下去!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值