JS实现页面右键菜单--优化版(二)

1,545 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

前言

右键菜单也算是前端页面中比较常见的功能了,根据需求的不同以及其他原因,将右键菜单功能分为两篇完成,本篇为优化版右键菜单。

上一篇简易版的右键菜单,已完成了右键菜单的基本功能,但它存在溢出的问题。

菜单溢出

菜单溢出就是在页面的边缘触发右键菜单时,由于触发点距离页面边缘距离小于右键菜单的宽度,所产生菜单显示不全的问题。

右键菜单溢出.gif

子菜单溢出

子菜单溢出也是一样的,就是菜单距离页面边缘的距离小于子菜单的宽度时,出现的子菜单显示不全问题。

右键子菜单菜单溢出.gif

解决溢出

首先,来回顾一下右键菜单的dom结构:

     <div id="menu" class="menu">
        <div class="menu__item" onclick="log('1')">功能1</div>
        <div class="menu__item" onclick="log('2')">功能2</div>
        <div class="menu__item" onclick="log('3')">功能3</div>
        <div class="menu__item">功能4 <span class="icon"> > </span>
            <div id="submenu" class="submenu">
                <div class="submenu__item" onclick="log('4-1')">功能4-1</div>
                <div class="submenu__item" onclick="log('4-2')">功能4-2</div>
                <div class="submenu__item" onclick="log('4-3')">功能4-3</div>
                <div class="submenu__item" onclick="log('4-4')">功能4-4</div>
            </div>
        </div>
        <div class="menu__item" onclick="log(5)">功能5</div>
    </div>

要解决溢出问题,我们就得先计算一下,menu.style.left最大值;

image.png

由图可知:

e.offsetX == window.innerWidth - menu.offsetWidth时,菜单刚好不会溢出,

e.offsetX > window.innerWidth - menu.offsetWidth时,菜单就会溢出;

所以,menu.style.left最大值是window.innerWidth - menu.offsetWidth

即,当e.offsetX >= window.innerWidth - menu.offsetWidth时,menu.style.left = window.innerWidth - menu.offsetWidth ;

e.offsetX < window.innerWidth - menu.offsetWidth时,menu.style.left = e.offsetX

    const menu=document.getElementById('menu');
    let x = e.offsetX;                //触发点到页面窗口左边的距离
    let winWidth = window.innerWidth; //窗口的内部宽度(包括滚动条)
    let menuWidth = menu.offsetWidth; //菜单宽度,高度包含内边距(padding)和边框(border),不包含外边距(margin)
    x = winWidth - menuWidth >= x ? x : winWidth -menuWidth;
    menu.style.left = x +'px';

解决子菜单溢出

解决子菜单溢出也是同理,在此基础上再减去子菜单的宽度即可。

image.png

    const submenu=document.getElementById('submenu');
    if(x > (winWidth -menuWidth - submenu.offsetWidth)){
        submenu.style.left = '-200px';
    }else{
        submenu.style.left ='';
        submenu.style.right ='-200px';
    }

最后效果

最后效果.gif

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .menu{
            position: absolute;
            top:0px;
            left: 0px;
            background: #fff;
            border: 1px solid #dadce0;
            visibility: hidden;
        }
        .active{
            visibility: visible;
        }
        .menu__item, .submenu__item{
            width: 200px;
            height: 20px;
        }
        .menu__item:hover, .submenu__item:hover{
            background-color: #dadce0;
        }
        .menu__item:hover .submenu{
            opacity: 1;
        }
        .submenu{
            position: relative;
            top:-20px;
            left: 200px;
            opacity: 0;
            background: #fff;
            border: 1px solid #dadce0;
        }
        .icon{
            position: absolute;
            right: 3px;
        }
    </style>
</head>
<body>
    <div id="menu" class="menu">
        <div class="menu__item" onclick="log('1')">功能1</div>
        <div class="menu__item" onclick="log('2')">功能2</div>
        <div class="menu__item" onclick="log('3')">功能3</div>
        <div class="menu__item">功能4 <span class="icon"> > </span>
            <div id="submenu" class="submenu">
                <div class="submenu__item" onclick="log('4-1')">功能4-1</div>
                <div class="submenu__item" onclick="log('4-2')">功能4-2</div>
                <div class="submenu__item" onclick="log('4-3')">功能4-3</div>
                <div class="submenu__item" onclick="log('4-4')">功能4-4</div>
            </div>
        </div>
        <div class="menu__item" onclick="log(5)">功能5</div>
    </div>
    <script>
        window.onload = function() {
            const menu=document.getElementById('menu');
            const submenu=document.getElementById('submenu');
            window.oncontextmenu=function(e){
                //取消默认的浏览器自带右键
                e.preventDefault();
                let x = e.offsetX;                //触发点到页面窗口左边的距离
                let y = e.offsetY;
                let winWidth = window.innerWidth; //窗口的内部宽度(包括滚动条)
                let winHeight = window.innerHeight;
                let menuWidth = menu.offsetWidth; //菜单宽度
                let menuHeight = menu.offsetHeight;
                x = winWidth - menuWidth >= x ? x : winWidth -menuWidth;
                y = winHeight - menuHeight >= y ? y : winHeight - menuHeight;
                menu.style.top = y+'px';
                menu.style.left = x +'px';
                if(x > (winWidth -menuWidth - submenu.offsetWidth)){
                    submenu.style.left = '-200px';
                }else{
                    submenu.style.left ='';
                    submenu.style.right ='-200px';
                }
                menu.classList.add('active');
            }
            // 关闭右键菜单
            window.addEventListener('click', function() {
                menu.classList.remove('active');
            })
        }
        // 菜单功能测试
        function log(i){
            alert(i);
        }
    </script>
</body>
</html>

到此优化版的右键菜单功能我们就实现了

如果大家还有什么其他想法,欢迎在评论区交流!