动态生成决策树

自己写之前,也上网搜过,不过没找到,所以现在将自己的代码发出来,希望可以帮到朋友们。

功能如下:

这里的弹出框调用的是bootsrap的组件,所以代码仅供参考,复制上去功能是出不来的,js具体代码如下:

/**
 * Created by heshuaishuai on 2017/3/6.
 */
define(
    [ "PDUtilDir/grid", "PDUtilDir/util", "PDUtilDir/tool",
        "PDUtilDir/dialog", "PDUtilDir/searchBlock",
        "CommonUtilDir/dict",
        "CommonUtilCkEditorDir/ckeditor","Date", "DateCN", "css!DateCss"  ],
    function(Grid, Util, Tool, Dialog, SearchBlock ,Dict) {
        //定义html全局变量
        var html = '';
        //定义一个具有初始值的json
        var treeJson = {
            ruleId:"",
            name:"规则",
            expression:"",
            id:"root"

        };

        /**
         * 创建根节点
         */
        function buildRoot(){
            html += '<div class="root" id="root">';
            html +=    '<span class="name btn btn-default">规则</span>';
            html +=    '<ul></ul>';
            html += '</div> ';
            return html;
        }

        /**
         * 创建左右分支
         */
        function bulidBranch(node) {
            branchStyle();
            html += '<div class="left" id='+node.yes.id+'>';
            html +=     '<span class="name btn btn-default"></span>';
            html +=        '<ul></ul>';
            html += '</div>';
            html += '<div class="right" id='+node.no.id+'>';
            html +=     '<span class="name btn btn-default"></span>';
            html +=        '<ul></ul>';
            html += '</div>';
            return html;
        }

        /**
         * 分支样式
         */
        function branchStyle(){
            html += '<div>';
            html +=     '<span class="vertical_left">成立</span>';
            html +=        '<span class="vertical_right">不成立</span>';
            html +=        '<span class="tran_left"></span>';
            html +=        '<span class="tran_right"></span>';
            html += '</div>';
            return html;
        }

        /**
         * 计算分支样式长度
         */
        function branchWidth(id){
            var array = id.split('-');
            var i = array.length-1;
            var w = $('#'+id+'>span.name').outerWidth();
            $('#'+id).width(w);
            if($('#'+id).attr('class') === 'left'){
                var parents_w = $('#'+id).parent('ul').parent('div').outerWidth();
                $('#'+id).css({'left':-(250-parents_w/2+w/2)+(i-1)*50+'px'});
            }
            if($('#'+id).attr('class') === 'right'){
                var parents_w = $('#'+id).parent('ul').parent('div').outerWidth();
                $('#'+id).css({'right':-(250-parents_w/2+w/2)+(i-1)*50+'px'});
            }
            $('#'+id+'>ul>div>span.tran_left').css({
                'width':250-i*50+'px',
                'left':-(250-w/2)+i*50+'px'

            });
            $('#'+id+'>ul>div>span.tran_right').css({
                'width':250-i*50+'px',
                'right':-(250-w/2)+i*50+'px'
            });
            $('#'+id+'>ul>div>span.vertical_left').css({
                'width':250-i*50+'px',
                'left':-(250-w/2)+i*50+'px'

            });
            $('#'+id+'>ul>div>span.vertical_right').css({
                'width':250-i*50+'px',
                'right':-(250-w/2)+i*50+'px'
            });
            $('#'+id+'>ul>div.left').css({'left':-(250-w/2+50)+i*50+'px'});
            $('#'+id+'>ul>div.right').css({'right':-(250-w/2+50)+i*50+'px'});
        }

        /**
         * 动态生成json
         */
        function createJson( id , nodeObj , name , expression ){
            var node = findNode(id , nodeObj );
            node.expression = expression;
            node.name = name;
            node['yes'] = {
                name:"",
                id:node.id+'-true',
                expression:""
            },
                node['no'] = {
                    name:"",
                    id:node.id+'-false',
                    expression:""
                }
        }


        /**
         * 核心算法:深度先序遍历获取当前node
         */
        function findNode( id , node ){
            //递归
            if( node ){
                if( node.id == id )
                    return node;
                if( node.yes ){
                    var tempNode = findNode( id , node.yes);
                    if( tempNode && tempNode.id == id )
                        return tempNode;
                }
                if( node.no){
                    var tempNode = findNode( id , node.no);
                    if( tempNode && tempNode.id == id )
                        return tempNode;
                }
            }
            return false;
        }

        /**
         * 获取高亮事件
         */
        function bindFocusEvent( id ){
            $('#' + id + '>span' ).unbind('click').bind( 'click' , function(){
                resetButtonStyle();
                $(this).addClass('btn-primary').removeClass('btn-default');
            });

        }

        /**
         * 点击添加条件表达式事件
         */
        function bindAddConditionButtonEvent(node){
            $('#add').unbind('click').bind('click' , function(){
                var currentNodeId = $('.btn-primary').parent('div').attr('id');
                if($('#'+currentNodeId+'>ul').html() ===''){
                    popUpAddConditionDialog( currentNodeId,node );
                }
            });
        }

        /**
         * 调用添加表达式弹出框,返回json,动态渲染
         */
        function popUpAddConditionDialog( id,node ){
            var currentNode = findNode( id , node );
            var buttons = [];
            buttons.push(
                {
                    name:"确定",
                    //回调函数
                    callback:function(){
                        var name = $('#conditionName').val();
                        var expression = $('#conditionExpression').val();
                        if(name === '' && expression === ''){
                            notNullDialog('条件名称与条件表达式不能为空!');
                        }else if(name === ''){
                            notNullDialog('条件名称不能为空!');
                        }else if(expression === ''){
                            notNullDialog('条件表达式不能为空!');
                        }else{
                            $('#' + id + ' >span').text(name);
                            createJson( id , currentNode , name , expression);
                            dialog.hide();
                            html = '';
                            $('#' + id + '>ul').empty();
                            $('#' + id + '>ul').append(bulidBranch(currentNode));
                            var childYesId = $('#' + id + ' >ul>.left').attr('id');
                            var childNoId = $('#' + id + ' >ul>.right').attr('id');
                            bindFocusEvent( childYesId );
                            bindFocusEvent( childNoId );
                            branchWidth(id);
                        }


                    }
                }
            );

            var dialog = Dialog({
                id:"BaseDialog",
                cache:false,
                title:"条件内容",
                "400px",
                hieght:"200px",
                dialogsize:"modal-sm",
                body:"",
                buttons:buttons
            });

            var dialogHtml = '';
            dialogHtml += '<form class="form-horizontal">';
            dialogHtml +=     '<div class="form-group">';
            dialogHtml +=        '<label class="col-sm-3">条 件 名 称:</label>';
            dialogHtml +=        '<input id="conditionName" class="col-sm-8" type="text"';
            dialogHtml +=        'placeholder="Conditional name" maxlength="20"/>';
            dialogHtml +=    '</div>';
            dialogHtml +=     '<div class="form-group">';
            dialogHtml +=        '<label class="col-sm-3">条件表达式:</label>';
            dialogHtml +=        '<textarea id="conditionExpression" class="col-sm-8"';
            dialogHtml +=        'placeholder="Conditional expression" maxlength="200"';
            dialogHtml +=        'rows="3"></textarea>';
            dialogHtml +=    '</div>';
            dialogHtml += '</form>';
            dialog.setBody(dialogHtml);
            dialog.show();
        }

        /**
         * 点击设置结果事件
         */
        function bindSetResultButtonEvent(node){
            $('#result').unbind('click').bind('click' , function(){
                var currentNodeId = $('.btn-primary').parent('div').attr('id');
                if($('#'+currentNodeId+'>ul').html() ===''){
                    popUpSetResultDialog( currentNodeId ,node);
                }
            });
        }

        /**
         *     调用设置结果弹出框
         */
        function popUpSetResultDialog( id ,node){
            var currentNode = findNode( id , node );
            var buttons = [];
            buttons.push(
                {
                    name:"确定",
                    //回调函数
                    callback:function(){
                        var name = $('#resultName').val();
                        var expression = $('#resultExpression').val();
                        if(name === '' && expression === ''){
                            notNullDialog('结果名称与结果表达式不能为空!');
                        }else if(name === ''){
                            notNullDialog('结果名称不能为空!');
                        }else if(expression === ''){
                            notNullDialog('结果表达式不能为空!');
                        }else{
                            $('#' + id + ' >span').text(name);
                            currentNode.name = name;
                            currentNode.expression = expression;
                            branchWidth(id);
                            dialog.hide();
                        }


                    }

                }
            );

            var dialog = Dialog({
                id:"BaseDialog",
                cache:false,
                title:"设置结果",
                "400px",
                hieght:"200px",
                dialogsize:"modal-sm",
                body:"",
                buttons:buttons
            });

            var dialogHtml = '';
            dialogHtml += '<form class="form-horizontal">';
            dialogHtml +=     '<div class="form-group">';
            dialogHtml +=        '<label class="col-sm-3">结 果 名 称:</label>';
            dialogHtml +=        '<input id="resultName" class="col-sm-8" type="text"';
            dialogHtml +=        'placeholder="Result name" maxlength="20"/>';
            dialogHtml +=    '</div>';
            dialogHtml +=     '<div class="form-group">';
            dialogHtml +=        '<label class="col-sm-3">结果表达式:</label>';
            dialogHtml +=        '<textarea id="resultExpression" class="col-sm-8"';
            dialogHtml +=        'placeholder="Result expression" maxlength="200"';
            dialogHtml +=        'rows="3"></textarea>';
            dialogHtml +=    '</div>';
            dialogHtml += '</form>';
            dialog.setBody(dialogHtml);
            dialog.show();
        }

        /**
         * 点击删除事件
         */
        function bindDeleteButtonEvent(node){
            $('#delete').unbind('click').bind('click' , function(){
                var currentNodeId = $('.btn-primary').parent('div').attr('id');
                var ulHtml = $('#'+currentNodeId+'>ul').html();
                if(ulHtml !=='' && ulHtml !==undefined){
                    popUpDeleteDialog( currentNodeId ,node);
                }
            });
        }

        /**
         *     调用删除弹出框
         */
        function popUpDeleteDialog( id ,node){
            var currentNode = findNode( id , node );
            var buttons = [];
            buttons.push(
                {
                    name:"确定",
                    //回调函数
                    callback:function(){
                        $('#'+id+' ul').empty();
                        $('#' + id + ' >span').text('');
                        currentNode.name = '';
                        currentNode.expression = '';
                        delete currentNode.yes;
                        delete currentNode.no;
                        dialog.hide();
                    }

                }
            );

            var dialog = Dialog({
                id:"BaseDialog",
                cache:false,
                title:"添加内容",
                "400px",
                hieght:"200px",
                dialogsize:"modal-sm",
                body:"确定删除吗?",
                buttons:buttons
            });
            dialog.show();
        }

        /**
         * 调用不能为空弹出框
         */
        function notNullDialog( text ){
            var buttons = [];
            buttons.push(
                {
                    name:"确定",
                    //回调函数
                    callback:function(){
                        dialog.hide();
                    }

                }
            );

            var dialog = Dialog({
                id:"BaseDialog",
                cache:false,
                title:"提示",
                "300px",
                hieght:"100px",
                dialogsize:"modal-sm",
                body:text,
                buttons:buttons
            });
            dialog.show();
        }

        /**
         * 重置样式
         */
        function resetButtonStyle(){
            $('#decisionTree .btn-primary').addClass('btn-default').removeClass('btn-primary');
        }

        /**
         * 根据json,深度遍历生成DOM结构
         */
        function generateDecisionTree(node){
            if(node){
                var suffix = branchPosition(node.id);
                if(suffix === 'root'){
                    html += '<div class="root" id='+node.id+'><span class="name btn btn-default">'+node.name+'</span><ul>';
                }

                if(node.yes && node.no){
                    if(suffix === 'true'){
                        html += '<div class="left" id='+node.id+'><span class="name btn btn-default">'+node.name+'</span><ul>';
                    }else if(suffix === 'false'){
                        html += '<div class="right" id='+node.id+'><span class="name btn btn-default">'+node.name+'</span><ul>';
                    }
                    branchStyle();
                }else{
                    if(suffix === 'true'){
                        html += '<div class="left" id='+node.id+'><span class="name btn btn-default">'+node.name+'</span><ul>';
                    }else if(suffix === 'false'){
                        html += '<div class="right" id='+node.id+'><span class="name btn btn-default">'+node.name+'</span><ul>';
                    }
                }

                if(node.yes){
                    generateDecisionTree(node.yes);
                }
                if(node.no){
                    generateDecisionTree(node.no);
                }
                html +='</ul></div>';
            }
            return html;
        }

        /**
         * 根据id后缀,判断左右分支
         */
        function branchPosition(id){
            var array = id.split('-');
            var length = array.length;
            var suffix = array[length-1];
            return suffix;
        }

        /**
         * 深度遍历:渲染后获取焦点
         */
        function getRenderFocus(node){
            bindFocusEvent( node.id );
            branchWidth(node.id);
            if(node.yes){
                getRenderFocus(node.yes);
            }
            if(node.no){
                getRenderFocus(node.no);
            }
        }

        /**
         * 点击生成,渲染页面
         */
        function bindGenerateButtonEvent(){
            $('#generate').unbind('click').bind('click',function(){
                html = '';
                $('#decisionTree').empty();
                $('#decisionTree').html(generateDecisionTree(treeJson));
                getRenderFocus(treeJson);
            });
        }

        /**
         * 点击保存,弹出json字符串
         */
        function bindSaveButtonEvent(node){
            $('#save').bind('click',function(){
                var treeString = JSON.stringify(node);
                alert(treeString);
            });
        }

        /**
         * 初始化数据
         */
        function initData(){
            $.ajax({
                type:'GET',
                url:getServer()+'/static/app/collection/decisionTree/treeJson.json',
                dataType:'JSON',
                success:function(data){
                    if(data){
                        if(data.ruleId === ''){
                            $('#decisionTree').html(buildRoot());
                            bindFocusEvent( 'root' );
                            init(treeJson);
                        }else{
                            html = '';
                            $('#decisionTree').empty();
                            $('#decisionTree').html(generateDecisionTree(data));
                            getRenderFocus(data);
                            init(data);
                        }
                    }
                }
            });
        }
        /**
         * 初始化
         */
        function init(node){
            bindAddConditionButtonEvent(node);
            bindSetResultButtonEvent(node);
            bindDeleteButtonEvent(node);
            bindSaveButtonEvent(node);
        }

        /**
         * 主函数
         */
        return {
            mainInit : initData
        }
    });

代码里三次用到了二叉树的先序遍历算法,核心算法也是二叉树的递归遍历算法,二叉树的递归遍历方法前面有说过。

还有朋友们可能会问我这个gif图是怎么录制的,给大家推荐一款神器LICEcap。

原文地址:https://www.cnblogs.com/hess/p/6626226.html