参考链接:

Element 组件之 右键鼠标 自定义菜单Vue+ElementUI实现给Tab页添加鼠标右键菜单栏

Element tree组件之 自定义菜单

基于element tree组件。效果图如下:

element右下角弹出框 element右键菜单_右键


1、 基于element组件 tree组件

2、 右键任何位置 基于鼠标位置跳转菜单

3、 类比于window鼠标右键一样的效果

4、 为什么基于elemet的右键菜单,因为,人家给封装好了 右键点击鼠标事件,以及点击鼠标右键事件时杀掉了系统的右击事件

链接地址:Element tree

基本思路:

给tree树绑定鼠标右键点击出发的事件 rightClick。当右击时出发函数,在函数中实现弹出右侧菜单栏事件 ,并且记录正在操作的 Node 。
这里使用的是element ui ,其帮我们关闭了默认的菜单弹出。

原声js

① 原生js方式实现时,要注意阻止弹出浏览器默认的菜单栏,即使用 e.preventDefault();
② 若跨组件了,则可以使用store的方式来对值进行存储和事件响应。

<style type="text/css">
        .menu__item {
            display: block;
            line-height: 20px;
            text-align: center;
            margin-top: 10px;
        }
        .menu {
            height: 100px;
            width: 100px;
            position: absolute;
            border-radius: 10px;
            border: 1px solid #999999;
            background-color: #f4f4f4;
        }
        li:hover {
            background-color: #1790ff;
            color: white;
        }

    </style>
</head>
<body>
    <div id="app">
        <!--
            :expand-on-click-node="false"  // 只能点击箭头才能显示子级列表
            @node-contextmenu="rightClick" // 鼠标右键触发的事件
            :highlight-current="true"	    // 高亮
            @node-click="handleNodeClick"> // 鼠标点击触发的事件
        -->
        <el-tree
                :data="data"
                :props="defaultProps"
                node-key="id"
                :expand-on-click-node="false"
                @node-contextmenu="rightClick"
                :highlight-current="true"
                @node-click="handleNodeClick"
        >
        </el-tree>
        <!--鼠标右键菜单栏,其实就是添加一个基于鼠标位置的模态框而已 -->

        <div v-show="menuVisible">
            <ul id="menu" class="menu">
                <li class="menu__item" @click="append(clickNode)">平级添加</li>
                <li class="menu__item" @click="addCard(clickNode)">下级添加</li>
                <li class="menu__item" @click="remove(clickNode)">删除</li>
            </ul>
        </div>
    </div>

</body>
<script type="application/javascript">
    new Vue({
        el: '#app',
        data: {
            menuVisible:false,
            data: [{
                id: 1,
                label: '一级 1',
                children: [{
                    id: 4,
                    label: '二级 1-1',
                    children: [{
                        id: 9,
                        label: '三级 1-1-1'
                    }, {
                        id: 10,
                        label: '三级 1-1-2'
                    }]
                }]
            }, {
                id: 2,
                label: '一级 2',
                children: [{
                    id: 5,
                    label: '二级 2-1'
                }, {
                    id: 6,
                    label: '二级 2-2'
                }]
            }, {
                id: 3,
                label: '一级 3',
                children: [{
                    id: 7,
                    label: '二级 3-1'
                }, {
                    id: 8,
                    label: '二级 3-2',
                    children: [{
                        id: 11,
                        label: '三级 3-2-1'
                    }, {
                        id: 12,
                        label: '三级 3-2-2'
                    }, {
                        id: 13,
                        label: '三级 3-2-3'
                    }]
                }]
            }],
            defaultProps: {
                children: 'children',
                label: 'label'
            },
            clickNode : '',
            id :14
        },
        defaultProps: {
            children: 'children',
            label: 'label'
        },
        methods: {
            handleNodeClick (data) {
                console.log(data);
            },
            rightClick (MouseEvent, object, Node, element) { // 鼠标右击触发事件
                this.menuVisible = false // 先把模态框关死,目的是 第二次或者第n次右键鼠标的时候 它默认的是true
                this.menuVisible = true  // 显示模态窗口,跳出自定义菜单栏
                var menu = document.querySelector('#menu')
                menu.style.left = MouseEvent.clientX + 5 + 'px'  // MouseEvent.clientX获取鼠标点击的坐标,在该处新增加的menu填充的位置
                menu.style.top = MouseEvent.clientY - 10 + 'px'
                document.addEventListener('click', this.foo) // 给整个document添加监听鼠标事件,点击任何位置执行foo方法
                console.log('右键被点击的event:', MouseEvent)
                console.log('右键被点击的object:', object)
                console.log('右键被点击的value:', Node)
                console.log('右键被点击的element:', element)
                console.log('鼠标点击了树形结构图')
                this.clickNode = Node  //存储待操作的节点或删除、或在该层或子层添加节点
                // alert(Node.level +":"+Node.label)
            },
            foo () { // 取消鼠标监听事件 菜单栏
                this.menuVisible = false
                document.removeEventListener('click', this.foo) // 要及时关掉监听,不关掉的是一个坑,不信你试试,虽然前台显示的时候没有啥毛病,加一个alert你就知道了
            },
            addCard (data) {
                const newChild = { id: this.id++, label: 'testtest', children: [] };
                //debugger
                if (!data.data.children) {
                    this.$set(data.data, 'children', []);// 最后一层节点添加下一层节点,先给其添加children属性
                }
                data.data.children.push(newChild);
            },
            remove (data) {
                //const newChild = { id: this.id++, label: 'testtest', children: [] };
                //debugger
                if (data.parent.data.children) {
                   return data.parent.data.children.pop(data.data) // 第一层以外的节点,父节点有children,从其父节点的children踢去该节点
                }
                data.parent.data.pop(data.data) // 第一层节点 ,父节点没有children从其父节点的children踢去该节点
            },
            append(data) {
                const newChild = { id: this.id++, label: 'testtest', children: [] };
                //debugger
                if (!data.parent.data.children) {
                   return  data.parent.data.push(newChild) // 第一层节点添加兄弟层级菜单栏
                }
                data.parent.data.children.push(newChild) // 第二层节点添加兄弟层级菜单栏
            },
        }
    })
</script>

附注: 原生js

① 原生js方式实现时,要注意阻止弹出浏览器默认的菜单栏,即使用 e.preventDefault();
② 若跨组件了,则可以使用store的方式来对值进行存储和事件

/*
右击事件
  */
openContextMenu(e) {
    e.preventDefault(); //防止默认菜单弹出
     
    let obj = e.srcElement ? e.srcElement : e.target;

    if (obj.id) {
        let currentContextTabId = obj.id.split("-")[1];
        let curIndex = 0;
        for(;curIndex<this.editableTabs.length;++curIndex){
            if(this.editableTabs[curIndex].title == currentContextTabId){
                break;
            }
        }
        if(curIndex<=0){
            this.isDisabledCloseLeftBtnFlag = true
            this.isDisabledCloseRightBtnFlag = false
        }else if(curIndex >= this.editableTabs.length-1){
            this.isDisabledCloseLeftBtnFlag = false
            this.isDisabledCloseRightBtnFlag = true
        }else{
            this.isDisabledCloseLeftBtnFlag = false
            this.isDisabledCloseRightBtnFlag = false
        }
        this.contextMenuVisible = true;
        this.$store.commit("saveCurContextTabId", currentContextTabId);
        this.left = e.clientX;
        this.top = e.clientY + 10;
    }
},