zoukankan      html  css  js  c++  java
  • [转]iView Cascader、Tree 数据处理

    原文地址:https://www.jianshu.com/p/1daf7d762502

        iView 有个 Cascader、Tree 组件,数据要求比较严格(简直弱爆了好吗...)

    问题简述

    Cascader 数据要求一览(Tree 其实类似):
    {
        value: 'jiangsu',
        label: '江苏',
        children: [
            {
                value: 'nanjing',
                label: '南京',
                children: [
                    {
                        value: 'fuzimiao',
                        label: '夫子庙',
                    }
                ]
            }, {
                value: 'suzhou',
                label: '苏州',
                children: [
                    {
                        value: 'zhuozhengyuan',
                        label: '拙政园',
                    }, {
                        value: 'shizilin',
                        label: '狮子林',
                    }
                ]
            }
        ]
    }

    即:

        value
        label
        children [可选]

    发个牢骚

    呃,谁的数据结构默认会是这样的?肯定很少,几乎没有....不服咬我

    话说就不能通过传递 value、label、children 的键值映射就配置 OK 了吗,非得每个使用的地方转一遍数据,累...就没爱过
    数据递归处理

    好吧,做完一个项目了,稍微整理整理...

    总得来说,这种数据还是比较好处理的。既然是树结构,其实和 Cascader 组件所要求的数据格式基本类似,无非字段名称不一样,字段可能更多而已。

    比如项目中某个需要展示部分数据:
    [
        {
            "department_id": 1,
            "department_name": "Test",
            "super_department_id": "0",
            "child_departments": [
                {
                    "department_id": "34",
                    "department_name": "修图",
                    "super_department_id": "1",
                    "child_departments": []
                },
                {
                    "department_id": "35",
                    "department_name": "系统研发",
                    "super_department_id": "1",
                    "child_departments": [
                        {
                            "department_id": "48",
                            "department_name": "测试组",
                            "super_department_id": "35",
                            "child_departments": []
                        },
                        {
                            "department_id": "49",
                            "department_name": "产品组",
                            "super_department_id": "35",
                            "child_departments": []
                        },
                        {
                            "department_id": "50",
                            "department_name": "运营",
                            "super_department_id": "35",
                            "child_departments": []
                        },
                        {
                            "department_id": "51",
                            "department_name": "技术开发组",
                            "super_department_id": "35",
                            "child_departments": []
                        }
                    ]
                }
            ]
        }
    ]

    那么需要做的转换如下:

        department_id -> value
        department_name -> label
        children -> child_departments

    这个做个简单的递归就解决了,代码、注释如下:
    /**
     * tree 数据转换
     * @param  {Array} tree 待转换的 tree
     * @return {Array}      转换后的 tree
     */
    function convertTree (tree) {
        const result = []

        // 遍历 tree
        tree.forEach((item) => {
            // 解构赋值
            let {
                department_id: value,
                department_name: label,
                child_departments: children
            } = item

            // 如果有子节点,递归
            if (children) {
                children = convertTree(children)
            }

            result.push({
                value,
                label,
                children
            })
        })

        return result
    }

    最终得到数据如下:
    [
        {
            "value": 1,
            "label": "Test",
            "children": [
                {
                    "value": "34",
                    "label": "修图",
                    "children": []
                },
                {
                    "value": "35",
                    "label": "系统研发",
                    "children": [
                        {
                            "value": "48",
                            "label": "测试组",
                            "children": []
                        },
                        {
                            "value": "49",
                            "label": "产品组",
                            "children": []
                        },
                        {
                            "value": "50",
                            "label": "运营",
                            "children": []
                        },
                        {
                            "value": "51",
                            "label": "技术开发组",
                            "children": []
                        }
                    ]
                }
            ]
        }
    ]

        在线演示地址:https://jsfiddle.net/Roam/5xxcjfk8/

    貌似结束了

    其实好像也就那么回事,十来行代码就敲定了。
    但是,回头一想,也不对,每种数据都要写个转换,也是神烦 = =
    好吧,继续优化优化吧...

    其实可以把递归函数再改改:
    /**
     * tree 数据转换
     * @param  {Array} tree 待转换的 tree
     * @param  {Object} map  键值对映射
     * @return {Array}      转换后的 tree
     */
    function convertTree (tree, map) {
        const result = []

        // 遍历 tree
        tree.forEach((item) => {
            // 读取 map 的键值映射
            const value = item[ map.value ]
            const label = item[ map.label ]
            let children = item[ map.children ]

            // 如果有子节点,递归
            if (children) {
                children = convertTree(children, map)
            }

            result.push({
                value,
                label,
                children
            })
        })

        return result
    }

    就是增加了一个 map 参数,用于指定 value、label、children 的字段映射:
    {
        value: 'department_id',
        label: 'department_name',
        children: 'child_departments'
    }

    这样这个递归方法就可以抽出来了,需要转换的地方,调这个方法就行了
    感觉可以提个 feature
    再来个复杂点的数据处理

    在做部门展示权限的时候,遇到个问题,简化如下:

        如果一个节点有权限,那么显示该节点,且显示所属的父节点
        如果该节点有权限,且该节点有子节点,子节点全部显示

    用图描述一下好了:
    selected-tree.png

        A 为 root 节点
        绿色表示有权限

    需要将上面的转换得到如下 tree 结构:
    filtered-tree.png

    用数据来说话就是:
     [
        {
            "name": "A",
            "children": [
                {
                    "name": "B",
                }, {
                    "name": "C",
                    "children": [
                        {
                            "name": "E",
                            "visible": true
                        }, {
                            "name": "F"
                        }
                    ]
                }, {
                    "name": "D",
                    "visible": true,
                    "children": [
                        {
                            "name": "G"
                        }, {
                            "name": "H"
                        }, {
                            "name": "I"
                        }
                    ]
                }
            ]
        }
    ]

    转成:
    [
        {
            "name": "A",
            "children": [
                {
                    "name": "C",
                    "children": [
                        {
                            "name": "E",
                            "visible": true
                        }
                    ]
                }, {
                    "name": "D",
                    "visible": true,
                    "children": [
                        {
                            "name": "G"
                        }, {
                            "name": "H"
                        }, {
                            "name": "I"
                        }
                    ]
                }
            ]
        }
    ]

    初看一脸懵逼
    再看还是一脸懵逼....

    细细捋一捋...

        遍历树
        如果当前节点有权限,塞进来
        如果当前节点无权限,并且无子节点,抛弃
        如果当前节点无权限,遍历子节点(重复如上)

    嗯~ o( ̄▽ ̄)o,就是这样的...

    这里有个技巧,就是使用 Array.prototype.filter()
     // 原始数据
     const raw = [
        {
            "name": "A",
            "children": [
                {
                    "name": "B",
                }, {
                    "name": "C",
                    "children": [
                        {
                            "name": "E",
                            "visible": true
                        }, {
                            "name": "F"
                        }
                    ]
                }, {
                    "name": "D",
                    "visible": true,
                    "children": [
                        {
                            "name": "G"
                        }, {
                            "name": "H"
                        }, {
                            "name": "I"
                        }
                    ]
                }
            ]
        }
    ]

    /**
     * Tree 过滤
     * @param  {Array} tree 待过滤的 tree
     * @return {Array}      已过滤的 tree
     */
    function filterTree (tree) {
        let result = []

        // filter 遍历
        result = tree.filter((item) => {
            // 如果有权限
            if (item.visible) {
                return true

            // 如果有子节点,递归子节点
            // 如果有权限,返回的值应该为非空数组
            } else if (item.children && item.children.length > 0) {
                item.children = filterTree(item.children)

                return item.children.length > 0

            // 抛弃
            } else {
                return false
            }
        })

        return result
    }

    console.log( JSON.stringify(filterTree(raw), null, 4) )

    // 打印结果
    // [
    //     {
    //         "name": "A",
    //         "children": [
    //             {
    //                 "name": "C",
    //                 "children": [
    //                     {
    //                         "name": "E",
    //                         "visible": true
    //                     }
    //                 ]
    //             },
    //             {
    //                 "name": "D",
    //                 "visible": true,
    //                 "children": [
    //                     {
    //                         "name": "G"
    //                     },
    //                     {
    //                         "name": "H"
    //                     },
    //                     {
    //                         "name": "I"
    //                     }
    //                 ]
    //             }
    //         ]
    //     }
    // ]

    其实也就十来行...

        在线演示链接:https://jsfiddle.net/Roam/5jb0r8y5/
        tree.gif

    总结

        递归是个好东西,能省很多代码(让我想起一个面试题...淡淡的忧伤)
        代码写得不顺手,肯定哪里有问题



  • 相关阅读:
    Mysql约束
    mysql数据库表的类型介绍
    Python之多进程根据p站画师id爬取
    Python‘最难’的问题——GIL问题
    MySQL数据库操作
    MySQL初识
    进程vs线程
    GIL锁
    Python冷知识
    python3利用smtplib发送、抄送邮件并附带附件
  • 原文地址:https://www.cnblogs.com/dirgo/p/12357376.html
Copyright © 2011-2022 走看看