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

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


前言

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

很基础的前端项目组织树,这边也是没有搭建环境,只是简单的引用了一个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>

效果图

目录
相关文章
|
4月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
423 2
|
3月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
375 137
|
6月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
351 0
|
7月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
907 0
|
9月前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
1180 4
|
7月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
8月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
1124 78
|
9月前
|
缓存 JavaScript 前端开发
Vue 基础语法介绍
Vue 基础语法介绍
|
6月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
540 1
|
7月前
|
JavaScript 前端开发 开发者
Vue 自定义进度条组件封装及使用方法详解
这是一篇关于自定义进度条组件的使用指南和开发文档。文章详细介绍了如何在Vue项目中引入、注册并使用该组件,包括基础与高级示例。组件支持分段配置(如颜色、文本)、动画效果及超出进度提示等功能。同时提供了完整的代码实现,支持全局注册,并提出了优化建议,如主题支持、响应式设计等,帮助开发者更灵活地集成和定制进度条组件。资源链接已提供,适合前端开发者参考学习。
546 17