重置网页右键菜单

网页右键菜单

使用的设计模式加方法:惰性单例+迭代

1、要求

  1. 在网页中鼠标右击后出现菜单,菜单中出现可选择的项,若有子菜单也需显示,就像浏览器自带的方法一样。在这里插入图片描述

2、思路

  1. 因为部分条目拥有子菜单在这里插入图片描述
    故首先需要设计数据对象的格式。
  2. 鼠标覆盖在菜单中的拥有 子菜单的 ‘li’ 上时需要弹出子菜单,所以有两种解决思路
    2.1 动态创建子菜单对象(首先使用的这种方法,后来因为粗心导致失败后放弃,后来在使用下面方法成功后察觉到问题所在)。
    2.2 在加载右键菜单时,将所有的菜单都加载出来,鼠标不在的隐藏(考虑到菜单的内容并不多,最后采用这种方法)。
  3. 鼠标覆盖判断
    3.1 鼠标覆盖时,若该条目存在子菜单则显示子菜单,鼠标离开该条目或子菜单时关闭子菜单(放弃该方法,也是这个思路导致了前面动态创建子菜单时出现bug)
    3.2 鼠标覆盖该条目时,遍历其它条目,关闭其它同级项目的子菜单,然后显示该条目的菜单(采用这种方法,避免了鼠标移开一级菜单到二级菜单时,二级菜单被关闭的情况)

3、实现

  1. 部分样式代码
<style>
        .list-box {
            position: absolute;
            border: 1px solid red;
        }

        .list-div {
            position: absolute;
            width: 150px;
            border: 1px solid #333;
        }
        .list-ul{
            position: absolute;
            list-style: none;
        }
        li {
            width: 150px;
            border: 1px solid yellowgreen;
        }
    </style>
  1. 确定的数据格式
var listData = [
                {
                    name: '百度',
                    url: 'https://www.baidu.com/',
                    child: [
                        { name: '百度一下', url: 'https://www.baidu.com/' },
                        { name: '百度翻译', url: 'https://fanyi.baidu.com/' }
                    ]
                },
                {
                    name: '腾讯',
                    url: 'https://www.qq.com/',
                    child: [
                        { name: '腾讯QQ', url: 'https://im.qq.com/', child: [{ name: 'QQ注册', url: 'https://ssl.zc.qq.com/v3/index-chs.html' }] },
                        { name: '腾讯视频', url: 'https://v.qq.com/' }
                    ]
                },
                {
                    name: '淘宝网',
                    url: 'https://www.taobao.com/'
                }
            ];
  1. js 相关代码
    3.1 屏蔽默认代码
// jQuery扩展代码
         $.createEle = function (params) {
            var tagName = params.tagName || 'div';
            var id = params.id || '';
            var className = params.className || '';
            var content = params.content || '';
            var css = params.css || {};
            var dom = document.createElement(tagName);
            if (id != '') { dom.id = id };
            if (className != '') { dom.className = className };
            if (content != '') { dom.innerHTML = content };
            for (var o in css) {
                dom.style[o] = css[o];
            }
            return dom;
        };
document.oncontextmenu = function (ev) {
// 屏蔽代码
            ev.preventDefault();
            var x = ev.clientX;
            var y = ev.clientY;
            // SelectBox 右键框单例
            var s = SelectBox.show({ left: x + 'px', top: y + 'px' });
        };   
        

3.2 单例代码

 var SelectBox = (function () {
            var listData = [
                {
                    name: '百度',
                    url: 'https://www.baidu.com/',
                    child: [
                        { name: '百度一下', url: 'https://www.baidu.com/' },
                        { name: '百度翻译', url: 'https://fanyi.baidu.com/' }
                    ]
                },
                {
                    name: '腾讯',
                    url: 'https://www.qq.com/',
                    child: [
                        { name: '腾讯QQ', url: 'https://im.qq.com/', child: [{ name: 'QQ注册', url: 'https://ssl.zc.qq.com/v3/index-chs.html' }] },
                        { name: '腾讯视频', url: 'https://v.qq.com/' }
                    ]
                },
                {
                    name: '淘宝网',
                    url: 'https://www.taobao.com/'
                }
            ];
            var _containBox = null;
            /**遍历数据
            obj:数据
            step:递归次数 控制展示位置
            topRow:距离顶部多少格 控制展示位置
            */
            function bianli(obj,step,topRow) {
                var ul = $.createEle({ tagName: 'ul', className: 'list-ul' });
                _containBox.appendChild(ul);
                ul.style.position='absolute';
                ul.style.left=150*step+'px';
                ul.style.top=20*topRow+'px';
                for (let i = 0; i < obj.length; i++) {
                    var liHTML = '<a href="' + obj[i].url + '">' + obj[i].name;
                    if (obj[i].child != null) {
                        liHTML += '&nbsp;&gt;</a>';
                    } else {
                        liHTML += '</a>';
                    };
                    var li = $.createEle({ tagName: 'li', className: 'list-ul-li', content: liHTML });
                    if (obj[i].child != null) {
                        li.child = bianli(obj[i].child,(step+1),(i+topRow));
                        li.child.style.display = 'none';
                        _containBox.appendChild(li.child);
                    };
                    li.onmouseover = function () {
                        for (var j = 0; j < ul.childNodes.length; j++) {
                            if (ul.childNodes[j] != li) {
                                ul.childNodes[j].closeChild();
                            }
                        }
                        if (this.child != null) {
                            this.child.style.display = 'block';
                        }
                    };
                    li.closeChild = function () {
                        if (this.child != null) {
                            this.child.style.display = 'none';
                            var childLis = this.child.childNodes;
                            for (var j = 0; j < childLis.length; j++) {
                                if (childLis[j].child != null) {
                                    childLis[j].child.style.display = 'none';
                                    for (var k = 0; k < childLis[j].child.childNodes.length; k++) {
                                        childLis[j].child.childNodes[k].closeChild();
                                    }
                                }
                            }
                        }
                    }
                    ul.appendChild(li);
                }
                return ul;
            };
            function getBox() {
                if (!_containBox) {
                    _containBox = $.createEle({ tagName: 'div', className: 'list-box' });
                    bianli(listData,0,0);
                    document.body.appendChild(_containBox);
                    _containBox.style.display = 'none';
                }

                return _containBox;
            };
            return {
                show: function (params) {
                    var Box = getBox();
                    Box.style.left = params.left;
                    Box.style.top = params.top;
                    Box.style.display = 'block';
                },
                close:function(){
                    var Box = getBox();
                    Box.style.display = 'none';
                    for(var i=0;i<_containBox.childNodes.length;i++){
                        if(i!=0){
                            _containBox.childNodes[i].style.display='none';
                        }
                    }
                }
            }
        })();

  1. 效果图
    在这里插入图片描述
  2. 总结
    5.1 样式
    样式方面就根据具体需求再美化了,部分距离设置方面可以配合 css 样式继续优化
    5.2 层数
    由于使用的迭代方法,所以只要数据中 child 不为 null 就可以无限嵌套,且无需手动调整。
    5.3 若是有需要的话也可以设计成 动态生成子菜单的形式,一切都看需要吧。还有在写代码的过程中一定要细心。起初一句代码少写了 ‘.display’,导致我检查了很久。都对自己的代码产生了怀疑。。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值