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()
};

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/883177.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

南开大学联合同济大学发布最新SOTA Occ OPUS:使用稀疏集进行占据预测,最快实现8帧22FPS

Abstract 占据预测任务旨在预测体素化的 3D 环境中的占据状态&#xff0c;在自动驾驶社区中迅速获得了关注。主流的占据预测工作首先将 3D 环境离散化为体素网格&#xff0c;然后在这些密集网格上执行分类。然而&#xff0c;对样本数据的检查显示&#xff0c;大多数体素是未占…

Windows内核编程基础(3)

内存分配 在应用层编程时&#xff0c;系统提供了GlobalAlloc/HeapAlloc/LocalAlloc等函数。C/C库提供了malloc函数&#xff0c;以及new操作符在堆上分配内存。 在我前面一个关于Windows页交换文件的博客中&#xff0c;介绍了虚拟内存&#xff0c; 虚拟内存是计算机系统内存管…

Unity开发绘画板——03.简单的实现绘制功能

从本篇文章开始&#xff0c;将带着大家一起写代码&#xff0c;我不会直接贴出成品代码&#xff0c;而是会把写代码的历程以及遇到的问题、如何解决这些问题都记录在文章里面&#xff0c;当然&#xff0c;同一个问题的解决方案可能会有很多&#xff0c;甚至有更好更高效的方式是…

Go容器化微服务系统实战

1-1 本课的go微服务有什么不同&#xff1f; 聚焦于容器化可观测的购物微服务系统实战&#xff0c;通过介绍Go语言的应用趋势、容器化优势及微服务适用性&#xff0c;旨在解决学习微服务过程中遇到的难点。课程内容涵盖微服务整体架构、技术工具框架及容器平台等关键技术&#…

Java之路--瓦解逻辑控制与方法使用已是瓮中捉鳖

嗨嗨大家&#xff01;今天我们来学习逻辑运算和方法的使用~ 目录 一 逻辑控制 1 分支结构 1.1 if语句 1.2 switch 语句 2 循环结构 2.1 while 循环 2.2 for 循环 2.3 do while 循环 2.4 break 2.5 continue 3. 输出输入 二、方法的使用 1 方法定义语法 2 实参和…

苹果macOS 15.0 Sequoia正式版发布:iPhone应用镜像玩、手机消息电脑知

9月17日苹果向 Mac 电脑用户推送了 macOS 15 更新&#xff08;内部版本号&#xff1a;24A335&#xff09;&#xff0c;除了引入数个 iOS 18 的新功能外&#xff0c;macOS 15 Sequoia 还带来了全新的 Continuity 功能 ——iPhone 镜像。 iPhone 镜像功能可以让用户直接在 Mac 上…

[Linux] Linux操作系统 进程的状态

标题&#xff1a;[Linux] Linux操作系统 进程的状态 个人主页&#xff1a;水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 一、前置概念的理解 1.并行和并发 2.时间片 3.进程间具有独立性 4.等待的本质 正文开始&#xff1a; 在校的时候&#xff0c;你一定学过《…

图解Transformer就这30页PPT,你们真不看啊

图解Transformer就这30页PPT&#xff0c;你们真不看啊 主要介绍了Seq2Seq模型&#xff0c;慢慢引出了transformer的整体模型架构&#xff0c;比较具体的介绍了编码器部分的数据处理过程&#xff0c;包括了位置编码、多头注意力机制、残差连接、Layer Norm以及前馈网络等基本结…

支付宝沙箱环境 支付

一 什么是沙箱&#xff1a; 沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境 支付宝正式和沙箱环境的区别 &#xff1a; AI&#xff1a; 从沙箱到正式环境&#xff1a; 当应用程序开发完成后&#xff0c;需要将应用程序从沙箱环境迁移到正式环境。 这通常涉及…

如何查看线程

1、首先找到我们的电脑安装jdk的位置&#xff0c;这里给大家展示一下博主本人的电脑jdk路径下的jconsole位置。 2、 ok&#xff0c;那么找到这个jconsole程序我们直接双击打开就可以查看我们电脑的本地进程&#xff1a; jconsole 这里能够罗列出你系统上的 java 进程&#xff0…

古代经典名方目录数据库-支持经典名方检索!

"古代经典名方目录"是指一系列历史上流传下来的&#xff0c;被认为具有一定疗效的中药方剂的汇总。这些方剂多来源于历代医学典籍&#xff0c;经过长期临床实践的检验&#xff0c;部分已被收录于官方的目录之中&#xff0c;以便于现代医疗实践中的参考和应用。 目前…

手机在网状态查询接口如何用C#进行调用?

一、什么是手机在网状态查询接口&#xff1f; 手机在网状态查询接口是利用实时数据来对手机号码在运营商网络中的状态进行查询的工具&#xff0c;包括正常使用状态、停机状态、不在网状态、预销户状态等。 二、手机在网状态查询适用哪些场景&#xff1f; 例如&#xff1a;商…

设计模式-结构型-11-代理模式

文章目录 1. 基本介绍2. 静态代理2.1 基本介绍UML 类图 2.2 应用实例定义接口目标对象代理对象调用代理 2.3 静态代理优缺点 3. 动态代理3.1 基本介绍3.2 JDK 中生成代理对象的 API参数说明UML类图 3.3 应用实例定义接口目标对象代理工厂调用代理 4. Cglib 代理4.1 基本介绍4.2…

求一个数的因子数(c语言)

1.计算并输出给定整数n的所有因子&#xff08;不包括1与n自身&#xff09;之和。规定n的值不大于1000。&#xff08;因子是能整除n的数 即n%i0&#xff09; // 例如&#xff0c;在主函数中从键盘给n输入的值为856&#xff0c;则输出为: sum763。 2.第一步我们先输入n的数&…

Koa (下一代web框架) 【Node.js进阶】

koa (中文网) 是基于 Node.js 平台的下一代 web 开发框架&#xff0c;致力于成为应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石&#xff1b; 利用 async 函数 丢弃回调函数&#xff0c;并增强错误处理&#xff0c;koa 没有任何预置的中间件&#xff0c;可快速…

mysql安装教程(新手版)

本教程不需要手动设置配置文件&#xff0c;比较简单&#xff0c;适合新手&#xff0c;过程需联网。 1.找到mysql官网 mysql官网 一.mysql的安装 1.界面如下图&#xff0c;点击箭头所指。 2.选择mysql版本&#xff0c;系统&#xff0c;安装。 3.下载完成后双击打开&#xff0…

golang操作mysql利器-gorm

1、傻瓜示例 GORM通过将数据库表中的数据映射到面向对象的模型中&#xff0c;简化了数据库操作&#xff0c;使得开发者可以很方便的使用代码来操作数据库&#xff0c;而无需编写SQL语句。 目前有个mysql表&#xff1a;miniprogram_orders&#xff0c;其存储了所有用户对应的订…

Android SystemUI组件(07)锁屏KeyguardViewMediator分析

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分即可。 为了更好理解本文的内容&#xff0c;优先说明下SystemUI中与Ke…

CoreDNS实现跨集群service解析实践

CoreDNS实现跨集群service解析实践 背景介绍使用条件实现方案 CoreDNS是一款使用Go语言实现的专为云原生应用而生的DNS服务器。本文介绍CoreDNS在特定实际场景下的一种进阶使用实践&#xff0c;也许能为其他也在使用CoreDNS做服务发现的同学提供一些启发和思考。 背景介绍 在…

luceda ipkiss教程 76:设计光栅耦合器

案例分享&#xff1a;设计光栅耦合器 全部代码如下&#xff1a; from si_fab import all as pdk from ipkiss3 import all as i3 import numpy as npclass grating_coupler(i3.PCell):"""SOI grating coupler."""_name_prefix "grating_c…