gaoshp
2024-03-23 bb130af2a7516017e584e4cc5f6fbf8ec2edbd36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<!--
 * @Descripttion: scContextmenu组件
 * @version: 1.1
 * @Author: sakuya
 * @Date: 2021年7月23日09:25:57
 * @LastEditors: sakuya
 * @LastEditTime: 2022年5月30日20:17:42
 * @other: 代码完全开源,欢迎参考,也欢迎PR
-->
 
<template>
    <transition name="el-zoom-in-top">
        <div v-if="visible" ref="contextmenu" class="sc-contextmenu" :style="{left:left+'px',top:top+'px'}" @contextmenu.prevent="fun">
            <ul class="sc-contextmenu__menu">
                <slot></slot>
            </ul>
        </div>
    </transition>
</template>
 
<script>
    export default {
        provide() {
            return {
                menuClick: this.menuClick
            }
        },
        data() {
            return {
                visible: false,
                top: 0,
                left: 0
            }
        },
        watch: {
            visible(value) {
                if (value) {
                    document.body.addEventListener('click', this.cm, true)
                }else{
                    document.body.removeEventListener('click', this.cm, true)
                }
            }
        },
        mounted() {
 
        },
        methods: {
            cm(e){
                let sp = this.$refs.contextmenu
                if(sp&&!sp.contains(e.target)){
                    this.closeMenu()
                }
            },
            menuClick(command){
                this.closeMenu()
                this.$emit('command', command)
            },
            openMenu(e) {
                e.preventDefault()
                this.visible = true
                this.left = e.clientX + 1
                this.top = e.clientY + 1
 
                this.$nextTick(() => {
                    var ex = e.clientX + 1
                    var ey = e.clientY + 1
                    var innerWidth = window.innerWidth
                    var innerHeight = window.innerHeight
                    var menuHeight = this.$refs.contextmenu.offsetHeight
                    var menuWidth = this.$refs.contextmenu.offsetWidth
                    //位置修正公示
                    //left = (当前点击X + 菜单宽度 > 可视区域宽度 ? 可视区域宽度 - 菜单宽度 : 当前点击X)
                    //top = (当前点击Y + 菜单高度 > 可视区域高度 ? 当前点击Y - 菜单高度 : 当前点击Y)
                    this.left = ex + menuWidth > innerWidth ? innerWidth - menuWidth : ex
                    this.top = ey + menuHeight > innerHeight ? ey - menuHeight : ey
                })
                this.$emit('visibleChange', true)
            },
            closeMenu() {
                this.visible = false;
                this.$emit('visibleChange', false)
            },
            fun(){
                return false;
            }
        }
    }
</script>
 
<style>
    .sc-contextmenu {position: fixed;z-index: 3000;font-size: 12px;}
    .sc-contextmenu__menu {display: inline-block;min-width: 120px;border: 1px solid #e4e7ed;background: #fff;box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);z-index: 3000;list-style-type: none;padding: 10px 0;}
    .sc-contextmenu__menu > hr {margin:5px 0;border: none;height: 1px;font-size: 0px;background-color: #ebeef5;}
    .sc-contextmenu__menu > li {margin:0;cursor: pointer;line-height: 30px;padding: 0 17px 0 10px;color: #606266;display: flex;justify-content: space-between;white-space: nowrap;text-decoration: none;position: relative;}
    .sc-contextmenu__menu > li:hover {background-color: #ecf5ff;color: #66b1ff;}
    .sc-contextmenu__menu > li.disabled {cursor: not-allowed;color: #bbb;background: transparent;}
    .sc-contextmenu__icon {display: inline-block;width: 14px;font-size: 14px;margin-right: 10px;}
    .sc-contextmenu__suffix {margin-left: 40px;color: #999;}
    .sc-contextmenu__menu li ul {position: absolute;top:0px;left:100%;display: none;margin: -11px 0;}
</style>