VUE条件树查询

看如下图所示的功能,是不是可高级了?什么,你没看懂?拜托双击放大看!

 是的,我最近消失了一段时间就是在研究这个玩意的实现,通过不懈努力与钻研并参考其他人员实现并加以改造,很好,终于有点小成果,这不就迫不及待给大家分享出来!使用的第三组件为VANT-X6引擎!

自己看官方文档:->https://x6.antv.antgroup.com/tutorial/getting-started

通过上述流后,可以任意组装出查询SQL语句或者是结构交给后端进行查询显示!这远比给定的那些搜索框框来的更加有性价比!用户搜索功能那就是嗖的一下提升了好多个档次。

来吧,到了最重要的环节,代码展示:

一、依赖安装

在项目的依赖包中添加以下依赖:最好按照我使用的版本添加哦,避免出现不兼容API报错无法运行!

"@antv/x6": "1.34.6",
"@antv/hierarchy": "0.6.8",
"@antv/x6-vue-shape": "1.3.2",
"@vue/composition-api":"1.3.0"

完成后,进行npm install或yarn install,取决于你使用的是什么环境脚本!

二、页面代码:

 queryGraph.vue 页面代码

<template>
    <div id="container" style="height: 100%;width:100%"></div>
</template>
<script>
import { Graph } from '@antv/x6'
import Hierarchy from '@antv/hierarchy'
import '@antv/x6-vue-shape'
import condition from './queryCondition.vue' //这是我的vue组件,作为子节点展示在思维导图上
import { findItem, lastChild, setData, addChildNode, removeNode, randomId } from './fun'


export default {
    data() {
        return {
            graphData: {
                'id': '1',
                'type': 'original—add',
                'width': 80,
                'height': 30,
                "children": [
                    // {
                    //     "id": 0.28207584597793156,
                    //     "type": "relative", //关系节点
                    //     "width": 44,
                    //     "height": 44,
                    //     "data": {
                    //         "relative": "and" //and并且 or或者
                    //     },
                    //     "children": [
                    //         {
                    //             "id": 0.32858917851150116,
                    //             "type": "condition-text", //条件节点
                    //             "width": 90,
                    //             "height": 44,
                    //             "level": 1, //判断它是第几级的条件节点
                    //             "edgeText": "",
                    //             "data": {
                    //                 "complete": true,
                    //                 "form": {} //你的业务数据
                    //             }
                    //         },
                    //         {
                    //             "id": 0.30546487070416783,
                    //             "type": "vue-shape", //自定义组件 业务节点
                    //             "width": 744,
                    //             "height": 44,
                    //             "level": 1,
                    //             "edgeText": "",
                    //             "data": {
                    //                 "complete": false,
                    //                 "form": {} //你的业务数据
                    //             }
                    //         }
                    //     ]
                    // }
                ]
            } //默认只有一个根节点
        }
    },
    mounted() {
        this.init()
    },
    methods: {
        //初始化⽅法
        init() {
            let self = this
            Graph.registerNode(
                'original—add',
                {
                    inherit: 'rect',
                    width: 80,
                    height: 30,
                    label: '+纳入条件',
                    attrs: { //样式代码
                        body: {
                            rx: 4,
                            ry: 4,
                            stroke: '#037AFB',
                            fill: '#037AFB',
                            strokeWidth: 1,
                            event: 'add:original' //根节点点击事件
                        },
                        label: {
                            fontSize: 14,
                            fill: 'white',
                            event: 'add:original'//根节点点击事件
                        }
                    }
                },
                true,
            )

            //表示《并且 或者》的关系节点
            Graph.registerNode(
                'relative',
                {
                    inherit: 'rect',
                    markup: [
                        {
                            tagName: 'rect',
                            selector: 'body'
                        },
                        {
                            tagName: 'text',
                            selector: 'label_text'
                        },
                        {
                            tagName: 'image',
                            selector: 'switch'
                        }
                    ],
                    attrs: { //样式代码
                        body: {
                            rx: 4,
                            ry: 4,
                            stroke: 'orange',
                            fill: 'orange',
                            strokeWidth: 1,
                            event: 'change:relative'
                        },
                        label_text: {
                            fontSize: 14,
                            fill: 'white',
                            event: 'change:relative'
                        },
                        switch: {
                            event: 'change:relative' //关系节点 切换 关系事件
                        },
                        text: { text: '并且' }
                    },
                    data: { relative: 'and' } //and并且 or或者 默认为 并且
                }
            )

            //自定义vue 业务节点
            Graph.registerVueComponent('condition', condition, true)

            //显示条件语句
            Graph.registerNode('condition-text',
                {
                    inherit: 'rect',
                    markup: [
                        {
                            tagName: 'rect',
                            selector: 'body'
                        },
                        {
                            tagName: 'g',
                            attrs: { class: 'content' },
                            children: []
                        }
                    ],
                    attrs: {}//样式代码
                }
            )
            // 弯的边
            Graph.registerEdge(
                'mindmap-edge',
                {
                    inherit: 'edge',
                    router: {
                        name: 'manhattan',
                        args: {
                            startDirections: ['right'],
                            endDirections: ['left']
                        }
                    },
                    connector: {
                        name: 'rounded'
                    },
                    attrs: {
                        line: {
                            targetMarker: '',
                            stroke: '#A2B1C3',
                            strokeWidth: 2
                        }
                    }, //样式代码
                    zIndex: 0
                },
                true,
            )

            // 直的边
            Graph.registerEdge(
                'straight-edge',
                {
                    inherit: 'edge',
                    attrs: {}, //样式代码
                    zIndex: 0
                },
                true,
            )

            //编辑
            Graph.registerNodeTool('edit', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -96, y: -72 },
                onClick({ cell }) {
                    const dataItem = cell.getData()
                    setData(this.graphData, cell.id, { ...dataItem, complete: false, isEdit: true })
                    cell.setData({ ...dataItem, complete: false, isEdit: true })
                    //打开编辑时,子级元素偏移
                    const firstChild = cell.getChildAt(0)
                    if (firstChild) {
                        const cellWidth = dataItem.form.unit ? 844 : 744
                        const x = cellWidth - firstChild.position({ relative: true }).x + 80 //编辑框 - 第一个子级位置 - 连接线宽 = 子级偏移量
                        cell.getChildAt(0).translate(x)
                    }
                }
            })

            //删除
            Graph.registerNodeTool('del', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -64, y: -72 },
                onClick({ cell }) {
                    if (removeNode(cell.id, this.graphData)) {
                        render(graph, this.graphData)
                    }
                }
            })

            //新增限定条件
            Graph.registerNodeTool('add-condition', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -32, y: -72 },
                onClick({ cell }) {
                    debugger
                    const { id } = cell
                    const dataItem = findItem(this.graphData, id).node
                    const lastNode = lastChild(dataItem)//找到当前node的最后一级,添加
                    if (addChildNode(lastNode.id, '并且', graphData)) render(graph, this.graphData)
                }
            })

            //关系节点 点击增加条件事件
            Graph.registerNodeTool('relative:add-condition', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -32, y: -72 },
                onClick({ cell }) {
                    debugger
                    const { id } = cell
                    if (addChildNode(id, '', this.graphData)) render(graph, this.graphData)
                }
            })

            //边增加条件
            Graph.registerEdgeTool('edge:add-condition', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            fontSize: 16,
                            width: 20,
                            height: 20,
                            rx: 2,
                            ry: 2,
                            stroke: '#296FFF',
                            strokeWidth: 1
                        }
                    },
                    {
                        tagName: 'text',
                        selector: 'label',
                        textContent: '+',
                        attrs: {
                            x: 5,
                            y: 15,
                            fontSize: 16,
                            cursor: 'pointer',
                            fill: '#ffff'
                        }
                    }
                ],
                distance: '100%',
                offset: { y: -10, x: -10 },
                onClick({ cell }) {
                    const { node, parent } = findItem(self.graphData, cell.target.cell)
                    const newId = randomId()
                    const childP = {
                        children: [node],
                        id: newId,
                        type: 'relative',
                        width: 40,
                        height: 40,
                        level: 2,
                        data: { relative: 'and', type: 'document' }
                    }
                    const currentIndex = parent.children.findIndex(item => item.id === node.id)
                    parent.children[currentIndex] = childP
                    let anode = addChildNode(newId, '', self.graphData)
                    anode.width = 550
                    if (anode) {
                        render(graph, self.graphData)
                    }

                    // const { node, parent } = findItem(self.graphData, cell.target.cell)
                    // const newId = randomId()
                    // const childP = {
                    //     id: newId,
                    //     type: "vue-shape", //自定义组件 业务节点
                    //     width: 550,
                    //     height: 44,
                    //     level: 1,
                    //     edgeText: "",
                    //     data: {
                    //         complete: false,
                    //         form: {} //你的业务数据
                    //     }
                    // }
                    // parent.children.push(childP)
                    // render(graph, self.graphData)
                }
            })

            let graph = new Graph({
                background: { color: '#fff' },
                container: document.getElementById('container'),
                panning: { enabled: true },
                selecting: { enabled: true },
                keyboard: { enabled: true },
                grid: true,
                mousewheel: {
                    enabled: true,
                    modifiers: ['ctrl', 'meta']
                },
                interacting: { nodeMovable: false }
            })

            const render = (graph, graphData) => {
                const result = Hierarchy.mindmap(graphData, {
                    direction: 'H',
                    getHeight(d) {
                        return d.height
                    },
                    getWidth(d) {
                        return d.width
                    },
                    getHGap() {
                        return 40
                    },
                    getVGap() {
                        return 20
                    },
                    getSide: () => {
                        return 'right'
                    }
                })
                const cells = []
                const traverse = (hierarchyItem, parentId) => {
                    if (hierarchyItem) {
                        const { data, children } = hierarchyItem
                        const node = graph.createNode({
                            ...data,
                            shape: data.type,
                            x: hierarchyItem.x,
                            y: hierarchyItem.y,
                            component: 'condition'
                        })
                        if (parentId) {
                            //有父级则插入父级
                            const parent = graph.getCellById(parentId)
                            parent && parent.addChild(node)
                        }
                        if (data.type === 'condition-text') {
                            //条件文案节点 根据文字长度,计算宽度,这边粗糙了点,将数字也按中文字长度计算,可优化
                            //下面是我的根据我的业务数据结构计算长度,可参考
                            //const { key, opt, value = [], unit } = data.data.form
                            //const keyText = key.displayText
                            //const optText = opt.displayText
                            //const valueText = typeof value === 'string' ? value : value.join(',')
                            //const unitText = valueText.length ? (unit || '') : ''
                            //const width = (keyText.length + optText.length + valueText.length + unitText.length) * 16 + 10

                            //node.attr('key/text', `${keyText},`)
                            //node.attr('opt', { text: `${optText} `, x: keyText.length * 16 + 5 })
                            //node.attr('value', { text: valueText, x: (keyText.length + optText.length) * 16 + 5 })
                            //node.attr('unit', { text: unitText, x: (keyText.length + optText.length + valueText.length) * 16 + 5 })
                            //node.resize(width, 44)
                            //data.width = width
                        }
                        //关系节点,默认是并且为蓝色,是或者的话,需要切换颜色判断
                        if (data.type === 'relative' && data.data.relative === 'or') {
                            node.setAttrs({
                                body: { stroke: '#CEE8D9', fill: '#CEE8D9' },
                                label_text: { fill: '#008451' },
                                switch: { 'xlink:href': "" },
                                text: { text: '或者' }
                            })
                        }
                        cells.push(node)
                        //子节点边
                        if (children) {
                            children.forEach((item) => {
                                const { id, data: itemData } = item
                                cells.push(
                                    graph.createEdge({
                                        shape: itemData.edgeText ? 'straight-edge' : 'mindmap-edge',
                                        source: {
                                            cell: hierarchyItem.id,
                                            anchor: {
                                                name: itemData.type === 'topic-child' ? 'right' : 'center',
                                                args: {
                                                    dx: itemData.type === 'topic-child' ? -16 : '25%'
                                                }
                                            }
                                        },
                                        target: { cell: id, anchor: { name: 'left' } },
                                        labels: [{ attrs: { text: { text: itemData.edgeText || '' } } }]
                                    }),
                                )
                                traverse(item, node.id)
                            })
                        }
                    }
                }
                traverse(result)
                graph.resetCells(cells)
                // graph.scaleContentToFit({ maxScale: 1 })
                graph.centerContent()
            }
            //根结点添加
            graph.on('add:original', ({ node }) => {
                debugger
                if (this.graphData.children.length == 0) {
                    const { id } = node
                    let anode = addChildNode(id, '', this.graphData)
                    anode.id = randomId()
                    anode.type = "vue-shape" //自定义组件 业务节点
                    anode.width = 550
                    anode.height = 44
                    anode.level = 1
                    anode.edgeText = ""
                    anode.data = {
                        complete: false,
                        form: {} //你的业务数据
                    }
                    anode.children = []
                    if (anode) {
                        render(graph, this.graphData)
                    }
                }
                else if (this.graphData.children.lastObject().type != 'relative') {
                    const { id } = node
                    let tlist = this.graphData.children
                    this.graphData.children = []

                        let anode = addChildNode(id, '', this.graphData)
                        anode.type = "relative"
                        anode.width = 40;
                        anode.height = 40;
                        anode.level = 1;
                        anode.data = {
                            "relative": "and" //and并且 or或者
                        }

                        let xlist = []
                        tlist.forEach(element => {
                            xlist.push(element)
                        });
                        xlist.push({
                            "id": randomId(),
                            "type": "vue-shape", //自定义组件 业务节点
                            "width": 550,
                            "height": 44,
                            "level": 1,
                            "edgeText": "",
                            "data": {
                                "complete": false,
                                "form": {} //你的业务数据
                            }
                        })
                        anode.children = xlist
                        if (anode) {
                            render(graph, this.graphData)
                        }
                }
                else 
                {
                    const { id } = node
                    let tlist = this.graphData.children
                    this.graphData.children = []

                    let anode = addChildNode(id, '', this.graphData)
                    anode.type = "relative"
                    anode.width = 40;
                    anode.height = 40;
                    anode.level = 1;
                    anode.data = {
                        "relative": "and" //and并且 or或者
                    }

                    let xlist = []
                    tlist.forEach(x=>{
                        xlist.push(x)
                    })
                    xlist.push({
                        "id": randomId(),
                        "type": "vue-shape", //自定义组件 业务节点
                        "width": 550,
                        "height": 44,
                        "level": 1,
                        "edgeText": "",
                        "data": {
                            "complete": false,
                            "form": {} //你的业务数据
                        }
                    })
                    anode.children = xlist
                    // tlist.push(anode)
                    this.graphData.children = [anode]
                    if (anode) {
                        render(graph, this.graphData)
                    }
                }
            })
            //节点数据变化
            graph.on('node:change:data', (cell) => {
                debugger
            })
            //关系节点 切换《并且或者》
            graph.on('change:relative', (cell) => {
                let node = cell.node
                if (node.data.relative == "and") {
                    node.data.relative = "or"
                    node.setAttrs({
                        body: {
                            stroke: '#d4eade',
                            fill: '#d4eade'
                        },
                        label_text: {
                            fontSize: 14,
                            fill: '#3e845e',
                        },
                        text: { text: '或者' }
                    })
                }
                else {
                    node.data.relative = "and"
                    node.setAttrs({
                        body: {
                            stroke: 'orange',
                            fill: 'orange'
                        },
                        label_text: {
                            fontSize: 14,
                            fill: 'white',
                        },
                        text: { text: '并且' }
                    })
                }
                debugger
                const dataItem = node.getData()
                setData(self.graphData,node.id,dataItem)
                debugger
            })
            //节点聚焦 增加工具栏目
            graph.on('node:mouseenter', ({ node }) => {
                // if (['condition-text', 'relative'].includes(node.shape)) {
                //     if (!this.isExistUnComplete()) { //判断当前是否有未填写完成的vue组件节点
                //         if (node.shape === 'condition-text') {
                //             node.setAttrs({ body: { fill: '#E9F0FF', stroke: '#296FFF' } })
                //         }
                //         this.addTool(node)
                //     }
                // }
            })
            //节点失焦 移除工具栏
            graph.on('node:mouseleave', ({ node }) => {
                // if (['condition-text', 'relative'].includes(node.shape)) {
                //     if (node.shape === 'condition-text') {
                //         node.setAttrs({ body: { stroke: '#CCC', fill: '#fff' } })
                //     }
                //     this.removeTool(node)
                // }
            })
            //边 悬浮事件
            graph.on('edge:mouseenter', ({ edge }) => {
                //不是 根结点下第一个关系节点 并且 没有未完成的节点 可添加
                const targetNode = graph.getCellById(edge.target.cell)
                const targetNodeData = findItem(this.graphData, edge.target.cell).node
                const isChild = targetNodeData.level ? targetNodeData.level === 1 : true //不是限定节点 可添加
                if (!(edge.source.cell === '1' && targetNode.shape === 'relative') && isChild && !this.isExistUnComplete()) {
                    edge.addTools(['edge:add-condition'])
                }
            })
            //边 失焦
            graph.on('edge:mouseleave', ({ edge }) => {
                if (!this.isExistUnComplete()) {//判断当前是否有未填写完成的vue组件节点
                    edge.removeTools(['edge:add-condition'])
                }
            })
            render(graph, this.graphData)
        },
        isExistUnComplete() {
            return false
        }
    }
}
</script>
<style lang="scss">
.topic-image {
    visibility: hidden;
    cursor: pointer;
}

.x6-node:hover .topic-image {
    visibility: visible;
}

.x6-node-selected rect {
    stroke-width: 2px;
}
</style>

三、自定义条件组件queryCondition.vue

<template>
    <div class="condition">
        <el-form ref="form" :model="form" label-width="0" inline>
            <el-row :gutter="10">
                <el-col :span=8>
                    <el-form-item class="w-100">
                        <el-input v-model="form.name" placeholder="搜索项目"></el-input>
                    </el-form-item>
                </el-col>
                <el-col :span=4>
                    <el-form-item class="w-100">
                        <el-select v-model="form.condition" placeholder="关系">
                            <el-option v-for="item in optionsList" :key="item.label" :label="item.label"
                                :value="item.value">
                            </el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span=7>
                    <el-form-item class="w-100">
                        <el-input v-model="form.text" placeholder="对比值"></el-input>
                    </el-form-item>
                </el-col>
                <el-col :span=5>
                    <el-from-item class="w-100">
                        <div class="flex-row w-100">
                            <el-button>取消</el-button>
                            <el-button type="primary" @click="onSubmit">确定</el-button>
                        </div>
                    </el-from-item>
                </el-col>
            </el-row>
        </el-form>
    </div>
</template>

<script>

// import { elForm, elFormItem, elInput, elSelect, elOption } from 'element-ui'//在这需要再次按需引入对应组件
export default {
    name: 'queryCondition',
    inject: ["getGraph", "getNode"],
    // components: { elForm, elFormItem, elInput, elSelect, elOption },
    data() {
        return {
            form: {
                name:null,
                condition:null,
                text:null
            },
            optionsList: [
                { label: '等于', value: '=' },
                { label: '不等于', value: '!=' },
                { label: '大于', value: '>' },
                { label: '大于等于', value: '>=' },
                { label: '小于', value: '<' },
                { label: '小于等于', value: '<=' }
            ]
        }
    },
    mounted() {
    },
    methods: {
        onSubmit(){}
    }
}
</script>

<style lang="scss" scoped>
.condition {
    padding: 0px 10px;
    height: 100%;
    background: #EFF4FF;
    border: 1px solid #5F95FF;
    border-radius: 6px;

    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
}


.flex-row{
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
}

::v-deep {
    .el-form-item--small {
        margin: 0px;
        vertical-align: middle !important;
    }

    .el-button--small{
        padding-left:10px;
        padding-right: 10px;
    }
}
</style>

四、公共方法 fun.js

import {snowFlakeId} from '@/utils/snowFlake'

//查找节点的父节点 当前节点,*节点的数据
export const findItem = (obj, id, levelTop) => {
    const topNode = levelTop
        ? levelTop
        : obj.level && obj.level === 1
        ? obj
        : null;
    if (obj.id === id) {
        return {
            parent: null,
            node: obj,
            topNode,
        };
    }
    const { children } = obj;
    if (children) {
        for (let i = 0, len = children.length; i < len; i++) {
            const res = findItem(children[i], id, topNode);
            if (res) {
                return {
                    parent: res.parent || obj,
                    node: res.node,
                    topNode: res.topNode,
                };
            }
        }
    }
    return null;
};
//查找最末级
export const lastChild = (obj) => {
    if (obj.children && obj.children.length) {
        return lastChild(obj.children[0]);
    } else {
        return obj;
    }
};
//设置某个节点的data
export const setData = (obj, id, dataItem) => {
    if (obj.id === id) {
        obj.data = dataItem;
        if (["vue-shape", "condition-text"].includes(obj.type)) {
            obj.type = dataItem.complete ? "condition-text" : "vue-shape";
        }
        return;
    }
    if (obj.children) {
        obj.children.forEach((child) => {
            setData(child, id, dataItem);
        });
    }
};

//插入节点
export const addChildNode = (id, edgeText, data) => {
    const res = findItem(data, id);
    const dataItem = res.node;
    if (dataItem) {
        const item = {
            id: randomId(),
            type: "vue-shape",
            width: 744,
            height: 44, //内容宽高 + padding20 + 边框4
            level: dataItem.level === 1 ? dataItem.level + 1 : 1,
            edgeText,
        };
        if (dataItem.children) {
            dataItem.children.push(item);
        } else {
            dataItem.children = [item];
        }
        return item;
    }
    return null;
};
//移除节点
export const removeNode = (id, data) => {
    const res = findItem(data, id);
    const dataItem = res.parent;
    if (dataItem && dataItem.children) {
        const { children } = dataItem;
        const index = children.findIndex((item) => item.id === id);
        children.splice(index, 1); //删除当前
        if (children.length && children.length < 2) {
            //并且或者 只有一个子级时 删除并且或者节点
            const p2 = findItem(data, dataItem.id).parent; //父级的父级
            const p2OtherChildren = p2.children.filter(
                (item) => item.id !== dataItem.id
            );
            p2.children = [...p2OtherChildren, ...children];
        }
        return true;
    }
    return null;
};

export const randomId = ()=> {
    return snowFlakeId()
};

目前只实现初步的效果,后期实现相关功能后再视具体是否可开放源码进行共享!

创作不易,谢谢你的点赞和关注收藏!

上一篇:重修设计模式-行为型-责任链模式


下一篇:过度广告是劣质护眼台灯的根源,为SUKER书客扼守护眼品质点赞