Skip to content

一个函数搞定右键菜单 #12

Description

@lzpong

一个函数搞定右键菜单,不啰嗦:

function Menu(id,target,cbFunfun,beforeShowFun){
    if(typeof(target)!="object")
        target=document.querySelector(target)||document.querySelector("#"+target);
    if(!target)
        return null;
    //如果吧`this`和`self`去掉,则会共用同一个menu对象
    this.menu= document.createElement("div");//菜单 Dom Object
    this.menu.id = id;
    this.menu.classList.add("menu");
    this.menu.innerHTML = '<div class="menu-line"></div>';
    this.cbFun=cbFunfun;//回调函数,点击菜单项事件  fun(id,text,menuid);
    this.cbBefore=beforeShowFun;//显示之前回调,更改菜单项enable/disable  fun(menuid)
    //CSS
    var stls=document.getElementsByTagName("style");
    for(i in stls){
      if(stls[i].className=="menu_css"){
        stls=1;break;
      }
    }
    if(stls!=1){
       var stl=document.createElement("style")
       stl.className="menu_css";
       stl.innerHTML=".menu{position:absolute;margin:0;padding:2px;min-width:114px;border:1px solid #ddd;background-color:#fafafa;box-shadow:2px 3px 8px 1px #b3b2b2;z-index:9999999;display:none}.menu-line{position:absolute;left:26px;top:0;height:100%;font-size:1px;border-left:1px solid #ccc;border-right:1px solid #fff}.menu-item{cursor:default;height:20px;font-size:12px;line-height:20px;padding-left:28px;background-repeat:no-repeat}.menu-disable{color:gray;opacity:.3}.menu-sep{border-top:1px solid #ccc;border-bottom:1px solid #fff;font-size:1px;margin:3px 0 3px 25px}.menu-active{background-color:#b7d2ff}";
       document.head.appendChild(stl);
    }

    this.menu.onclick = onMenuClick;
    this.menu.onmouseout = onMenuMouseOn;
    this.menu.onmouseover = onMenuMouseOn;
    document.body.appendChild(this.menu);
    target.oncontextmenu = onContextMenu;
    this.target=null;//右键点击的对象
    var self=this;
    //show,,左/下边不超出
    function show(x,y){
        self.menu.style.opacity=0;
        self.menu.style.display = "block";
        if (document.body.offsetWidth < x + self.menu.offsetWidth)
            self.menu.style.left = document.body.offsetWidth-self.menu.offsetWidth + "px";
        else
            self.menu.style.left = x + "px";
        if (document.body.offsetHeight < y + self.menu.offsetHeight)
            self.menu.style.top = document.body.offsetHeight-self.menu.offsetHeight + "px";
        else
            self.menu.style.top = y + "px";
        self.menu.style.opacity=null;
    }
    //右键菜单
    function onContextMenu(e) {
        self.target=e.target;
        if(self.cbBefore)
            self.cbBefore(self.menu.id);
        show(e.clientX,e.clientY);
        document.addEventListener("click", OnDocClick, false);
        return false;
    }
    //控制菜单item高亮
    function onMenuMouseOn(e) {
        var cls = e.target.classList;
        //console.log(e.type,e.target);
        if (cls.contains("menu-item"))
        {
            if (e.type == "mouseover") {//进入
                cls.add("menu-active");
            } else if (e.type == "mouseout") {//移出
                cls.remove("menu-active")
            }
        }
    }
    //菜单item点击
    function onMenuClick(e) {
        cls = e.target.classList;
        if(self.cbFun && cls.contains("menu-item") && !cls.contains("menu-disable"))
            self.cbFun(e.target.id,e.target.innerText,self.menu.id,self.target);
    }
    //其他点击,关闭菜单
    function OnDocClick(e) {
        self.target=null;
        cls = e.target.classList;
        if (!(cls.contains("menu") || cls.contains("menu-line") || cls.contains("menu-sep")) && !cls.contains("menu-disable")){
            self.menu.style.display = "none";
            document.removeEventListener("click", OnDocClick);
        }
    }

    //text为空则插入间隔条,icon大小:20*20
    function insertItem(id,text,icon){
        var itm=document.createElement("div");
        if(text==null || text==""){
            itm.classList.add("menu-sep")
        }else{
            itm.id=id;
            if(icon && icon.length>3)
                itm.style.backgroundImage="url("+icon+")";
            itm.innerHTML=text;
            itm.classList.add("menu-item")
        }
        self.menu.appendChild(itm);
    }
    //设置item 可用/不可用
    function setAble(id,able){
      var itm=self.menu.querySelector("#"+id);
      if(itm){
        var disabled=itm.classList.contains("menu-disable");
        if(able && disabled)
            itm.classList.remove("menu-disable");
        else if(!able && !disabled)
            itm.classList.add("menu-disable");
      }
    }
    function clear(){
        var line=self.menu.firstElementChild;
        while(itm=line.nextElementSibling)
            itm.remove();
    }

    return {
        getID:function(){return self.menu.id;},
        insertItem:insertItem,
        clear:clear,
        setAble:setAble,
        show:show,
    }
}

使用方法:

<style>
.ddiv{
width:200px;
height:300px;
margin:10px;
display:inline-flex;
border: 1px solid rgb(204, 204, 204);
}
</style>
<div id="div1" class="ddiv">div1</div>
<div id="div2" class="ddiv">div2</div>
<div id="div3" class="ddiv">div3</div>
/*菜单回调函数参数:
 * id: 菜单选项ID
 * txt:菜单选项文字
 * menuid:菜单ID
 * target:右键点击的对象
*/
function onClick(id,txt,menuid,target){
console.log(id,txt,menuid,target);
}
//
var menu1=new Menu("menu1","div1",onClick);
menu1.insertItem("d1-1","item1m1放到","https://p.ssl.qhimg.com/t01f41d7d4e86418577.png");
menu1.insertItem("d1-2","item2m1范德萨范德萨","https://p.ssl.qhimg.com/t01f41d7d4e86418577.png");
menu1.insertItem("d1-3","item3m1按时");
menu1.insertItem();
menu1.insertItem("d1-4","item4m1按时");
menu1.setAble("d1-1",false);

//
var menu2=new Menu("menu2","div2",onClick);
menu2.insertItem("d2-1","item1m2");
menu2.insertItem("d2-2","item2m2");
menu2.insertItem("d2-3","item3m2");
menu2.insertItem();
menu2.insertItem("d2-4","item4m2");
menu2.setAble("d2-2",false);

//
var menu3=new Menu("menu3","div3",onClick);
menu3.insertItem("d3-1","item1m3");
menu3.insertItem("d3-2","item2m3");
menu3.insertItem("d3-3","item3m3");
menu3.insertItem();
menu3.insertItem("d3-4","item4m3");
menu3.setAble("d3-3",false);

直观图:
image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions