为了账号安全,请及时绑定邮箱和手机立即绑定

树形操作2-或、且关系组合

标签:
JavaScript

树形操作数据整理总结,这篇是第二篇。本篇是关于树节点拖拽组合,实现或、且的关系,并支持删除节点。demo 是基于 jquery 及 easy-ui 库实现的。

  • 截图:

5c3c95f90001bc5f01640034.jpg

5c3c95f90001774109540612.jpg

具体实现-loading:

利用 css3 实现。主要运用了 :before:after 选择器‘画’了两个圆点,最后利用animationtransform:translateX() scale()实现动画。利用位移模拟的旋转,为了使效果更好,加了一点点缩放。

html:

<div class="loading"></div>

css:

.loading {    position: relative;    height: 100%;    line-height: 100%;
}.loading:before,.loading:after {    position: absolute;    top: calc(50% - 5px);    left: calc(50% - 5px);    content: "";    width: 10px;    height: 10px;    border-radius: 100%;
}.loading:before {    background: skyblue;    animation: loading-reverse .8s linear infinite; 
}.loading:after {    background: yellow;    animation: loading .8s linear infinite; 
}
@keyframes loading {    from {        transform: translate(-20px) scale(.8);
    }    to {        transform: translate(20px) scale(1.1);
    }
}
@keyframes loading-reverse {    from {        transform: translate(20px) scale(.8);
    }    to {        transform: translate(-20px) scale(1.1);
    }
}

本想用一个 loading + reverse 实现,但实现效果不是很理想,就用了两个。下面是一个 loading 的代码,可以试一下。

.loading:before {    background: skyblue;    animation: loading .8s linear infinite reverse; 
}.loading:after {    background: yellow;    animation: loading .8s linear infinite; 
}
@keyframes loading {    from {        transform: translate(-20px) scale(.8);
    }    to {        transform: translate(20px) scale(1.1);
    }
}

具体实现:

html 结构比较简单,左右布局;左边是外加了一个 tab 切换及筛选。右侧,默认一个清空按钮。结构如下:

<div class="tree-drag-relation">    <div class="left">
        <ul class="nav loading" id="nav"></ul>
        <div class="search tree-header" id="search">
            <input class="search-input" placeholder="搜索标签" value="" />
        </div>
        <ul class="tree-con loading" id="tree_drag"></ul>
    </div>
    <div class='right'>
        <div class="relation-header">
            <span class="tip-num">已重组节点(<span class="num" id="node_num">0</span>)</span>
            <span class="clear-all" id="clear_all">清空</span>
        </div>
        <div class="relation-con and-wrap" id="relation_con">
        </div>
    </div></div>

为了使 js 代码逻辑清晰,结构组织分为了左右 2 部分。左侧,负责 tab 切换及树形数据的展示等,结构如下:

5c3c95fa000117fb06760473.jpg

右侧负责 或、且 逻辑的处理、删除、展示及回填等,结构如下:

5c3c95fa0001ab9f08300576.jpg

tab 切换
tab 切换比较简单,就不上代码了。

树形展示
数据树形展示,利用的是 easyui 插件的 tree 插件,按照官方 API,很容易就能实现。

关键点一:要求数据格式为:

[{
    id: '',
    text: '',
    children: [{}] // 依次类推
}]

关键点二:设置支持拖拽,且在加载成功后,设置当前树节点不可放置被拖拽的节点。具体可看renderDragTree这个方法。

treeDragMod.$treeTarget.tree({    data: treeData,    dnd: true, // 允许拖拽
    formatter: function(node) {        // 统计子节点个数
        var text = '<span class="node-name">' + node.text + '</span>';        if (node.children && node.children.length > 0) {
            text += '<i class="tip">(' + node.children.length + ')</i>';
        }        return text;
    },    onLoadSuccess: function(e, node) {        // 折叠树
        treeDragMod.$treeTarget.tree('collapseAll');        
        // 节点上禁止放置
        $.each($('#tree_drag .tree-node'), function(i, item) {
            $(item).droppable("disable");
        });
    }
});
relationMod.setDragAndDrop();

关键点三:放置,或且的渲染。拖拽实现的另一个点就是放置,因此另一个关键点就是设置放置点,并进行放置逻辑处理,这是实现 或、且 关系的重点。具体可看setDragAndDrop方法实现。

//设置被拖元素$("#tree_drag .tree-node").draggable({
    proxy: 'clone',
    revert: true, //拖动结束后节点将返回它的开始位置
    cursor: 'pointer',
    onStartDrag: function () {
        $(this).draggable('proxy').css({'background': '#fff', 'opacity': '0.5'});
    },
    onStopDrag: function (e) {        var $target = $(e.target),
            node = $('#tree_drag').tree('getNode', e.data.target), // 获取被拖动的节点
            $clearAll = $('#clear_all');        
        // 判断在可拖拽放置区域,才进行放置操作
        if ($target.hasClass('and-wrap') || $target.hasClass('or-wrap')) {
            $clearAll.show();
            $target.append(conHtml());
        }        function conHtml (relation) {            // 处理 and 且的关系
            var conHtml = '';            if ($target.hasClass('and-wrap')) {                if ($target.children().length) {
                    conHtml += relationMod.andHtml;
                }                var innerHtml = node.children ? relationMod.orConHtml(node.children) : relationMod.orItemHtml(node);
                conHtml += relationMod.orWrapLeftHtml + innerHtml + '</div>';
            } else if ($target.hasClass('or-wrap')) { // 处理 or 或的关系
                if ($target.children().length) {
                    conHtml += relationMod.orHtml;
                }
                conHtml += node.children ? relationMod.orConHtml(node.children) : relationMod.orItemHtml(node);
            }            return conHtml;
        }

        relationMod.setNodeNum();
        relationMod.resizeScrollTop();
    }
});// 设置目标对象允许放置被拖元素$(".and-con, .or-con").droppable();

或、且关系添加时,是通过判断当前添加节点的元素是否有子元素,有那么添加元素的时候,就需要添加对应的关系。考虑,添加元素没有子节点时,是只需添加节点,而不需要添加关系。

关键点四:节点删除。

5c3c95fb00014a6c02040288.jpg

假如箭头为或且,第一次删除ABC都正确。

采用删除字母的同时,判断,上一个箭头存在,则需要删除上一个,否则需要删除下一个箭头。

删除 或 item 的如下:

$('body').on('click', '.item-del', function () { // 删除 item
    var $this = $(this),
        $item = $this.closest('.item'),
        $orWrap = $this.closest('.or-wrap');    // 删除当前元素及关系
    // 上一个存在,删上一个,否则删下一个
    var $prev = $item.prev('.or');    if ($prev.length) {
        $prev.remove();
    } else {        var $next = $item.next('.or');        if ($next.length) {
            $next.remove();
        }
    }
    $item.remove();    // 删除后,若其父元素无子元素,则删除其父元素
    if ($orWrap.children('.item').length == 0) {
        $orWrap.remove();
    }

    relationMod.setNodeNum();
})

删除且的逻辑和这个类似。

其他操作比较简单,就不赘述了,具体实现可看github 源代码

最后就是,目前实现的方案,只支持二级树结构,多级是不支持的。

原文出处:https://www.cnblogs.com/EnSnail/p/10268643.html 

作者:ESnail 

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消