angular-tree-control树的实现

前言:最近接了一个活,将一大堆数据通过左边树结构展示出来。对左边树可勾选后,右边展示左边树勾选过的内容,最终保存右边树入库。

效果图

效果图
数据动态绑定显示

  • 节点开合
  • 选择和未选择状态切换
  • 左边树选择部分右边树展示
  • 右边树点x则左边树取消选择
上代码:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/angular.js/1.6.3/angular.min.js"></script>
    <script type="text/javascript" src="js/angular-tree-control.js"></script>
    <script src="./js/context-menu.js"></script>
    <link rel="stylesheet" type="text/css" href="css/tree-control.css">
    <link rel="stylesheet" type="text/css" href="css/tree-control-attribute.css">
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css">
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.slim.min.js"></script>
    <script src="https://cdn.bootcss.com/popper.js/1.12.9/umd/popper.min.js"></script>
    <script src="https://cdn.bootcss.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
    <style>
        .height-500 {
            height: 500px;
        }

        .margin-top-100 {
            margin-top: 100px;
        }

        pre {
            outline: 1px solid #ccc;
            padding: 5px;
            margin: 5px;
        }

        .string {
            color: green;
        }

        .number {
            color: darkorange;
        }

        .boolean {
            color: blue;
        }

        .null {
            color: magenta;
        }

        .key {
            color: red;
        }
    </style>
</head>
<body>
<div class="container" ng-controller="myController">
    <div class="row margin-top-100">
        <div class="col-sm p-3 mb-2 bg-info text-white height-500">
            <treecontrol class="tree-light"
                         tree-model="dataForTheTree"
                         options="treeOptions"
                         selected-nodes="selectedNodes">

                <label ng-click="showSelected(node)">
                    <input type="checkbox"
                           ng-model="node.checked"
                           class="check-box" disabled>
                    {{node.id}}
                </label>
            </treecontrol>
        </div>
        <div class="col-sm p-3 mb-2 bg-dark text-white height-500">
            <treecontrol class="tree-dark"
                         tree-model="selectedTree"
                         options="treeOptions1"
                         selected-nodes="selectedNodes">
                <label>
                    <input type="checkbox"
                           ng-model="node.checked"
                           class="check-box" disabled>
                    <label>
                        {{node.id}}
                    </label>
                    <label ng-show="showClose(node)" ng-click="dirSelectedStatusNeedRemoveById(node.id)">
                        x
                    </label>
                </label>
            </treecontrol>
        </div>
    </div>
    <div class="row">
        <div class="col-sm">
            <h1>左边树</h1>
            <pre>
                <div ng-bind-html='dataForTheTree| jsonFormat | showAsHtml'></div>
            </pre>
        </div>
        <div class="col-sm">
            <h1>右边树</h1>
            <pre>
                <div ng-bind-html='selectedTree| jsonFormat | showAsHtml'></div>
            </pre>
        </div>
        <div class="col-sm">
            <h1>已经选中的节点</h1>
            <pre>
                <div ng-bind-html='selectedNodes| jsonFormat | showAsHtml'></div>
            </pre>
        </div>
    </div>
</div>
<script>
    const app = angular.module('myApp', ['treeControl']);
    app.controller('myController', function ($scope) {
        let vm = $scope;
        // 左边树选择的内容
        vm.selectedNodes = [];
        // 右边树展示内容
        vm.selectedTree = [];
        vm.treeOptions = {
            nodeChildren: "children",
            dirSelectable: true,
            injectClasses: {
                ul: "a1",
                li: "a2",
                liSelected: "a7",
                iExpanded: "a3",
                iCollapsed: "a4",
                iLeaf: "a5",
                label: "a6",
                labelSelected: "a8"
            },
            multiSelection: true
        };
        vm.treeOptions1 = {
            nodeChildren: "children",
            dirSelectable: false,
            injectClasses: {
                ul: "a1",
                li: "a2",
                liSelected: "a7",
                iExpanded: "a3",
                iCollapsed: "a4",
                iLeaf: "a5",
                label: "a6",
                labelSelected: "a8"
            },
            isSelectable: function () {
                return false;
            }
        };
        vm.dataForTheTree = [{
            "id": "Joe",
            "fid": "-1",
            "checked": false,
            "children": [
                {"id": "Smith", "fid": "Joe", "checked": false, "children": []},
                {
                    "id": "Gary",
                    "checked": false,
                    "fid": "Joe",
                    "children": [{
                        "id": "Jenifer",
                        "fid": "Gary",
                        "checked": false,
                        "children": [
                            {"id": "Dani", "checked": false, "fid": "Jenifer", "children": []},
                            {"id": "Max", "checked": false, "fid": "Jenifer", "children": []}
                        ]
                    }]
                }
            ]
        },
            {"id": "Albert", "checked": false, "fid": "-1", "children": []},
            {"id": "Ron", "checked": false, "fid": "-1", "children": []}
        ];
        // 将左边树选中的同步给右边的树,全量同步,效率略差于增量同步
        $scope.$watch('dataForTheTree', function () {
            if (!!$scope.dataForTheTree && $scope.dataForTheTree.length > 0) {
                let treeDataRightTmp = JSON.parse(JSON.stringify($scope.dataForTheTree));
                $scope.selectedTree = createObjectTree(treeDataRightTmp);
            }
        }, true);
        // 切换节点的选中状态
        function toggleSelect(node) {
            node.checked = !node.checked;
            vm.dataForTheTree.push();
        }
        vm.showSelected = function (node) {
            toggleSelect(node);
            selectFollowNodesIfDir(node);
            dirSelectedStatusNeedRemove(vm.dataForTheTree);
        };

        vm.showClose = function (node) {
            return node.children.length === 0;
        };

        // 判断父级别节点是否需要删除(一个父节点下没有任何被选中的节点则该节点需要被删除)
        function dirSelectedStatusNeedRemove(tree) {
            tree.forEach(n => {
                if (isDir(n)) {
                    if (!dirHasSelectedNode(n)) {
                        n.checked = false;
                        removeFromSelectedNodes(n);
                    }
                    dirSelectedStatusNeedRemove(n.children);
                }
            })
        }

        vm.dirSelectedStatusNeedRemoveById = function (id) {
            closeById(vm.dataForTheTree, id);
            vm.dataForTheTree.push();
            dirSelectedStatusNeedRemove(vm.dataForTheTree);
            vm.dataForTheTree.push();
        };

        function closeById(tree, id) {
            for (let i = 0; i < tree.length; i++) {
                let node = tree[i];
                if (node.id === id) {
                    node.checked = false;
                    removeFromSelectedNodes(node);
                    return;
                }
                if (isDir(node)) {
                    closeById(node.children, id);
                }
            }
        }

        // 查找节点下所有非父级别节点是否有被选中,一个也没有则返回false
        function dirHasSelectedNode(node) {
            let result = false;
            let treeNode = node.children;
            for (let i = 0; i < treeNode.length; i++) {
                let childNode = treeNode[i];
                // 如果非选中并且是父级别节点则迭代找该节点下的是否有勾选状态的节点
                if (isDir(childNode)) {
                    if (dirHasSelectedNode(childNode)) {
                        result = true;
                        break
                    }
                } else {
                    if (childNode.checked) {
                        result = true;
                        break
                    }
                }
            }
            return result;
        }

        // 创建目标树
        function createObjectTree(tree) {
            for (let i = tree.length - 1; i >= 0; i--) {
                let node = tree[i];
                if (isDir(node)) {
                    // 先去删除根
                    createObjectTree(node.children);
                    // 没有根的,删除父级别元素
                    if (node.children.length === 0) {
                        tree.splice(i, 1);
                    }
                } else {
                    // 删除根级别元素
                    if (!node.checked) {
                        tree.splice(i, 1);
                    }
                }
            }
            return tree;
        }

        // 判断是否是父节点
        function isDir(node) {
            return !!node && !!node.children && node.children.length > 0;
        }

        // 选中父节点则勾选父节点下所有节点
        function selectFollowNodesIfDir(node) {
            if (isDir(node)) {
                // 遍历dir下面的节点
                node.children.forEach(n => {
                    // 节点状态和dir节点不一致,则把节点状态改成与dir节点状态一致
                    if (node.checked !== n.checked) {
                        n.checked = node.checked;
                        n.checked ? vm.selectedNodes.push(n) : removeFromSelectedNodes(n);
                        selectFollowNodesIfDir(n);
                    }
                });
            }
        }

        // 节点取消勾选情况下,从已选中数组中删除该节点
        function removeFromSelectedNodes(node) {
            let index = vm.selectedNodes.indexOf(node);
            if (index !== -1) {
                vm.selectedNodes.splice(index, 1);
            }
        }
    });
    app.filter('jsonFormat', function () {
        return function (json) {
            return syntaxHighlight(json);
        }
    });
    app.filter("showAsHtml", function ($sce) {
        return function (input) {
            return $sce.trustAsHtml(input);
        }
    });

    function syntaxHighlight(json) {
        if (!json) {
            return json;
        }
        if (typeof json !== 'string') {
            json = JSON.stringify(json, undefined, 2);
        }
        json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
        return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
            let cls = 'number';
            if (/^"/.test(match)) {
                if (/:$/.test(match)) {
                    cls = 'key';
                } else {
                    cls = 'string';
                }
            } else if (/true|false/.test(match)) {
                cls = 'boolean';
            } else if (/null/.test(match)) {
                cls = 'null';
            }
            return '<span class="' + cls + '">' + match + '</span>';
        });
    }
</script>
</body>
</html>

参考文献:
[1]:https://github.com/wix/angular-tree-control
[2]: https://blog.csdn.net/weixin_38496860/article/details/81166907
[3]: https://www.runoob.com/angularjs/angularjs-tutorial.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Angular中使用angular-gridster库,可以通过使用其提供的事件和方法来获取拖拽后的数据。 首先,我们需要在HTML文件中设置Gridster组件,并声明一个用于展示数据的数组: ```html <gridster [options]="gridsterOptions" (gridsterItemChange)="onItemChange($event)"> <gridster-item *ngFor="let item of gridsterItems" [item]="item"> <!-- content --> </gridster-item> </gridster> ``` 在组件的.ts文件中,需要定义gridsterOptions和gridsterItems变量,并使用相关的事件和方法来获取拖拽后的数据: ```typescript import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { gridsterOptions = { // gridster options }; gridsterItems = [ // initial items ]; onItemChange(event: any) { // get gridster item change event console.log(event); // here you can access the dragged item's updated data } } ``` 在onItemChange方法中,可以通过event参数访问拖拽后的数据。它包含了当前拖拽的GridsterItemComponent实例,我们可以从中获取更新后的数据。 例如,可以通过event.item获取更新后的位置信息、尺寸信息等。如果有其他自定义的数据需要获取,可以在GridsterItemComponent中设置相关属性并在event.item中访问。 以上是使用angular-gridster获取拖拽后数据的基本方法,你可以根据自己的需求进行进一步定制和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值