您的当前位置:首页正文

【vue】设计组织机构树,增删改查,右键导航树弹出菜单对点前节点增删改,特殊字符校验

2024-11-23 来源:个人技术集锦

前言

前端二面试题,话不多说看题~

很基础的前端项目组织树,这边也是没有搭建环境,只是简单的引用了一个vue2库,保存到了本地直接引用加快访问。

功能

1.默认展示树内容
2.鼠标右击出现菜单
3.实现添加节点、删除节点、修改节点

代码 html

效果图先放最后

<!DOCTYPE html>
<html lang="">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>menu</title>
    <script src="./vue.min.js"></script>
</head>

<body>
    <div id="app">
        <p>选择节点ID:{{hoverId}}&emsp;下一个ID:{{lastId}}</p>
        <div class="box" @click.right="fnRightClick($event)" @click.left="fnLeftClick($event)">
            <div class="tree" v-html="treeHtml"></div>
        </div>
        <div class="menu" v-if="menuVisibleState" :style="{left: menuLeft,top: menuTop}">
            <div class="btn" @click="fnOpenCreate()"><span>新增</span></div>
            <div class="btn" @click="fnOpenModify()"><span>修改</span></div>
            <div class="btn" @click="fnDelete()"><span>删除</span></div>
        </div>
        <div class="wrapper" v-if="formVisibleState">
            <div class="dialog">
                <div class="form">
                    <div>
                        <label for="name">组织名称:</label>
                        <input type="text" id="name" v-model="name">
                    </div>
                    <div>
                        <label for="desc">组织描述:</label>
                        <textarea rows="10" id="desc" v-model="desc"></textarea>
                    </div>
                    <div class="btn-group">
                        <button @click="fnCommit()">提交</button>
                        <button @click="fnCloseCreate()">取消</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        component: {},
        data: {
            id: '',
            name: '',
            desc: '',
            treeHtml: '',
            hoverId: '',
            lastId: 12,
            detail: {},
            menuLeft: 0,
            menuTop: 0,
            menuVisibleState: false,
            formVisibleState: false,
            orgDataList: [
                {
                    id: 1, label: '1', desc: '',
                    children: [
                        {
                            id: 4, label: '1-1', desc: '',
                            children: [
                                { id: 5, label: '1-1-1', desc: '', children: [] }
                            ]
                        },
                        {
                            id: 10, label: '1-2', desc: '',
                            children: [
                                { id: 11, label: '1-2-1', desc: '', children: [] }
                            ]
                        }
                    ]
                },
                {
                    id: 2, label: '2', desc: '',
                    children: [
                        {
                            id: 6, label: '2-1', desc: '',
                            children: [
                                { id: 7, label: '2-1-1', desc: '', children: [] }
                            ]
                        }
                    ]
                },
                {
                    id: 3, label: '3', desc: '',
                    children: [
                        {
                            id: 8, label: '3-1', desc: '',
                            children: [
                                { id: 9, label: '3-1-1', desc: '', children: [] }
                            ]
                        }
                    ]
                }
            ],
        },
        methods: {
            // 左击
            fnLeftClick() {
                this.menuVisibleState = false
            },
            // 右击
            fnRightClick(event) {
                event.preventDefault()
                let e = event
                this.menuLeft = e.clientX + "px"
                this.menuTop = e.clientY + "px"
                this.menuVisibleState = true
            },
            // 打开创建窗口
            fnOpenCreate() {
                this.menuVisibleState = false
                this.formVisibleState = true
            },
            // 打开修改窗口
            fnOpenModify() {
                this.menuVisibleState = false
                this.formVisibleState = true
                fnOperateNode(this.hoverId, [], this.orgDataList, 'detail')
                this.id = this.detail.id
                this.name = this.detail.label
                this.desc = this.detail.desc
                this.children = this.detail.children
            },
            // 删除
            fnDelete() {
                fnOperateNode(this.hoverId, [], this.orgDataList, 'delete')
                this.menuVisibleState = false
            },
            // 关闭创建窗口
            fnCloseCreate() {
                this.formVisibleState = false
            },
            // 提交
            fnCommit() {
                if (app.id) {
                    let val = {
                        id: app.id,
                        label: app.name,
                        desc: app.desc,
                        children: app.children
                    }
                    fnOperateNode(app.id, val, app.orgDataList, 'modify')
                    fnGeneratorTreeNode(app.orgDataList)
                    app.id = ''
                } else {
                    let val = {
                        id: app.lastId,
                        label: app.name,
                        desc: app.desc,
                        children: []
                    }
                    if (app.hoverId) {
                        fnOperateNode(app.hoverId, val, app.orgDataList, 'create')
                    } else {
                        app.$set(app.orgDataList, app.orgDataList.length, val, 'create')
                        fnGeneratorTreeNode(app.orgDataList)
                    }
                    app.lastId = app.lastId + 1
                }
                app.formVisibleState = false
                app.id = ''
                app.name = ''
                app.desc = ''
                app.children = []
            }
        }
    });

    // 修改节点
    function fnOperateNode(id, val, dataList, type) {
        if (dataList && dataList.length) {
            for (let i = 0; i < dataList.length; i++) {
                if (dataList[i] && dataList[i].id == id) {
                    if (type == 'create') {
                        app.$set(dataList[i].children, dataList[i].children.length, val)
                        fnGeneratorTreeNode(app.orgDataList)
                    } else if (type == 'detail') {
                        app.detail = dataList[i]
                    } else if (type == 'modify') {
                        dataList[i] = val
                        fnGeneratorTreeNode(app.orgDataList)
                    } else if (type == 'delete') {
                        dataList.splice(i, 1)
                        console.log(app.orgDataList)
                        fnGeneratorTreeNode(app.orgDataList)
                    }
                } else if (dataList[i].children && dataList[i].children.length) {
                    fnOperateNode(id, val, dataList[i].children, type)
                }
            }
        }
    }

    // 悬浮选中ID
    function fnSetHoverId(id) {
        app.hoverId = id
    }

    // 移除悬浮选中ID
    function fnUnsetHoverId() {
        app.hoverId = ''
    }

    // 生成根节点 html
    function fnGeneratorTreeNode(dataList) {
        app.treeHtml = ''
        dataList.forEach((item) => {
            if (item) {
                app.treeHtml += '<div class="node"><div class="content"><span οnmοuseenter="fnSetHoverId(' + item.id + ')">' + item.label + '</span>';
                if (item.children && item.children.length) {
                    app.treeHtml += fnGeneratorLeafNode(item.children)
                }
                app.treeHtml += '</div></div>'
            }
        })
    }

    // 生成叶节点 html
    function fnGeneratorLeafNode(dataList) {
        let content = ''
        for (let i = 0; i < dataList.length; i++) {
            content += '<div class="node"><div class="content"><span οnmοuseenter="fnSetHoverId(' + dataList[i].id + ')">' + dataList[i].label + '</span>';
            if (dataList[i].children && dataList[i].children.length) {
                content += fnGeneratorLeafNode(dataList[i].children)
            }
            content += '</div></div>'
        }
        return content
    }

    fnGeneratorTreeNode(app.orgDataList)

</script>
<style>
    * {
        padding: 0;
        margin: 0;
    }

    html,
    body {
        width: 100%;
        height: 100%;
    }

    ul {
        list-style: none;
    }

    #app {
        width: 100%;
        height: 100%;
    }

    .box {
        width: 100%;
        height: 100%;
        background-color: #ffffff;
    }

    .menu {
        width: 100px;
        height: auto;
        position: fixed;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        border: 1px solid #000000;
        border-radius: 5px;
        background-color: #ffffff;
    }

    .menu .btn {
        width: 80px;
        height: 20px;
        padding: 10px;
        text-align: center;
    }

    .menu .btn:hover {
        background-color: black;
    }

    .menu .btn:hover span {
        color: #ffffff;
    }

    .tree {
        padding: 50px;
    }

    .node {
        padding-left: 20px;
        width: 100%;
        height: 100%;
        cursor: pointer;
    }

    .wrapper {
        width: 100%;
        height: 100%;
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 1000;
        background-color: black;
        opacity: 0.7;
        text-align: center;
    }

    .dialog {
        width: 320px;
        height: 300px;
        z-index: 1001;
        background-color: #ffffff;
        display: inline-block;
        vertical-align: middle;
        text-align: left;
    }

    .wrapper:after {
        height: 100%;
        width: 0px;
        content: "";
        display: inline-block;
        text-align: center;
        vertical-align: middle;
    }

    .form {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-items: start;
        justify-content: left;
        padding: 20px;
    }

    .form input {
        width: 280px;
        line-height: 25px;
        margin-bottom: 10px;
    }

    .form textarea {
        width: 280px;
    }

    button {
        width: 50px;
        height: 30px;
    }

    label {
        font-size: 14px;
    }

    .btn-group {
        margin-bottom: -1px;
    }
</style>

</html>

效果图

显示全文