This commit is contained in:
2022-04-25 13:40:12 +08:00
commit 41f187e460
349 changed files with 60741 additions and 0 deletions
@@ -0,0 +1,97 @@
# contextMenu
自由定制页面元素的右键菜单。
![demo](https://github.com/yuri2peter/contextMenu/blob/master/pre.png?raw=true)
> 是的同类的插件很多,作者造轮子是因为当初寻找右键菜单插件的时候,找了几个都有bug,要么经不起环境的考验,只能跑通demo。如果你也在寻找一款右键菜单插件,不如试试这一款,应该不会让你失望。
## 最新版本
v2.2.5
## 原理
该插件通过指定的参数,渲染出一个漂亮的右键菜单,并绑定菜单项点击事件。
需要的参数有:
1. 右键事件e。指定一个事件e,它可能是通过原生js、jq,甚至vue捕捉的;该插件将获取点击的位置,并阻止事件冒泡,屏蔽默认的右键菜单。
2. 菜单描述数组menu。menu数组决定了你想渲染出什么样的菜单。
## 特色
* 侵入性小,这个插件几乎不会影响全局,除了ContextMenu全局变量。
* 兼容性好,在各个屏幕尺寸和有无滚动条的场景都有不错的渲染效果。
* 支持多层嵌套的DOM触发的事件,以最里层为准(详见demo)。
* 支持二级菜单。
## 准备
1. 下载源码(并点赞)
2. 引入 jquery
3. 引入 contextMenu.css
4. 引入 contextMenu.js
## 典型用法
~~~js
$('body').contextmenu(function (e) {
var menu=[
'menu1', //合理的html或纯文字
'menu2',
'|', //分隔符
[
'click me', //title
function (dom) {alert('Hi')} // 点击菜单项的回调
],
];
ContextMenu.render(e,menu,this); //开始渲染
});
~~~
## API
`ContextMenu.render(e,menu,param,theme)`
**e**:点击事件对象,如`$('body').contextmenu(function (e){})`
**menu**:
menu为`true`代表禁用系统默认菜单,但是不渲染自定义菜单;
menu为数组表示渲染自定义右键菜单;
~~~js
var menu=[
'文字1', //纯文字或html将直接被渲染,做为一个提示性菜单项
'文字2',
'|', //简单的一个分隔符
['功能1',function(param){alert("功能1点击")}], //这种格式说明这个菜单项可以被点击并产生回调
[
'子菜单',[
'文字3',
'文字4',
'|',
['功能2',function(param){alert("功能2点击")}],
]
] //声明一个子菜单,子菜单内部的声明格式和父级一样
]
~~~
**param**:菜单点击回调的第一个参数
**theme**:主题(目前可选主题"light"
## 其他
注意:为了获得正确的屏幕尺寸,添加了一个`html,body:{height:100%}`的样式,请确保该样式生效不被覆盖。
## 更多项目
[Yuri2'Projects](https://github.com/yuri2peter/)
## TOOD
* 右键菜单,二级垂直方向有可能溢出
## 更新记录
* v2.2.5 修复文字溢出(title提示)和子菜单底部溢出
* v2.2.3 优化css
* v2.2.2 新增第三个参数[bool] disable 临时禁用菜单点击功能 `['功能2',function(param){alert("功能2点击")},true]`
* v2.2.1 优化css
* v2.2.0 新增主题切换功能
* v2.1.1 修复了二级菜单溢出屏幕的问题,更好的兼容性
@@ -0,0 +1,92 @@
html, body {
height: 100%;
padding: 0;
margin: 0;
}
.yuri2-context-menu {
left: 0;
top: 0;
position: fixed;
width: 150px;
height: auto;
background-color: rgb(61, 61, 61);
display: block;
/*border-radius: 5px;*/
z-index: 99999999;
color: white;
/*overflow: hidden;*/
}
.yuri2-context-menu.sub {
left: 98%;
position: absolute;
display: none;
}
.yuri2-context-menu.sub.left {
left: auto;
right: 98%;
}
.yuri2-context-menu ul li:hover .yuri2-context-menu.sub {
display: block;
}
.yuri2-context-menu ul.left .yuri2-context-menu.sub{
left: -100%;
}
.yuri2-context-menu ul {
margin: 0px;
padding: 0px;
box-shadow: 0 0 16px rgba(0, 0, 0, 0.54);
}
.yuri2-context-menu ul li {
transition: background-color 0.5s;
cursor: default;
padding: 0px 1em;
list-style: none;
line-height: 30px;
height: 30px;
font-size: 10px;
/*overflow: hidden;*/
position: relative;
}
.yuri2-context-menu ul li div.title{
width: 80%;
overflow: hidden;
height: 100%;
float: left;
word-break: break-all;
}
.yuri2-context-menu ul li div.title.disable {
color: darkgrey;
}
.yuri2-context-menu ul li.sub:after {
content: ">";
float: right;
transform: scale3d(0.5,1.5,1);
position: relative;
}
.yuri2-context-menu ul li:hover {
background-color: #636363;
}
.yuri2-context-menu ul li a {
text-decoration: none;
display: block;
height: 100%;
color: #333;
outline: none;
}
.yuri2-context-menu ul hr {
margin: 0;
height: 0;
border: 0;
border-bottom: rgba(132, 132, 132, 0.47) 1px solid;
border-top: none
}
/*浅色主题*/
.yuri2-context-menu.light {background-color: #e0e0e0;border-color: #535353;color: #333333;}
.yuri2-context-menu.light ul li:hover {background-color: #707070;color: #ffffff;}
.yuri2-context-menu.light ul hr{border-color: #535353;}
@@ -0,0 +1,96 @@
/**
* contextMenu v2.2.4
* @author Yuri2(yuri2peter@qq.com)
* @link https://github.com/yuri2peter/contextMenu
* Enjoy! (●'◡'●)
* 基于jq的右键菜单(动态绑定)
* @author Yuri2
*/
window.ContextMenu={
_className:'yuri2-context-menu',
_stopProp:function (e) {
if (e.cancelable) {
// 判断默认行为是否已经被禁用
if (!e.defaultPrevented) {
e.preventDefault();
}
}
e.stopImmediatePropagation();
e.stopPropagation();
},
_getMainContent:function(text){
return text.replace(/<\/?.+?>/g,"");
},
render:function (e, menu, trigger,theme) {
theme||(theme='');
var x=e.clientX,y=e.clientY;
this._stopProp(e);
this._removeContextMenu();
if(menu===true){return;}
if(typeof menu === 'object' && menu.length===0){menu=[['...']]}
var dom = $("<div class='"+ContextMenu._className+" "+theme+"'><ul></ul></div>");
$('body').append(dom);
var ul=dom.find('ul');
if(x+150>document.body.clientWidth){x-=150;ul.addClass('left')}
menu.forEach(function (item) {
if(item==='|'){
ul.append($('<hr/>'));
}
else if(typeof(item)==='string'){
ul.append($('<li><div class="title" title="'+ContextMenu._getMainContent(item)+'">'+item+'</div></li>'));
}
else if(typeof(item)==='object'){
var sub=$('<li><div class="title '+(item[2]===true?'disable':'')+'" title="'+ContextMenu._getMainContent(item[0])+'">'+item[0]+'</div></li>');
ul.append(sub);
if(typeof(item[1])==='object'){
var subMenu=$("<div class='sub "+ContextMenu._className+" "+theme+"'>\</div>");
var subUl=$("<ul></ul>");
sub.addClass('sub');
subMenu.append(subUl);
if(x+300>document.body.clientWidth){subMenu.addClass('left')}
sub.append(subMenu);
var counterForTop = -1;
item[1].forEach(function (t) {
if(t==='|'){
subUl.append($('<hr/>'));
}
else if(typeof(t)==='string'){
subUl.append($('<li><div class="title" title="'+ContextMenu._getMainContent(t)+'">'+t+'</div></li>'));
counterForTop++;
}
else if(typeof(t)==='object'){
var subLi=$('<li><div class="title '+(t[2]===true?'disable':'')+'" title="'+ContextMenu._getMainContent(t[0])+'">'+t[0]+'</div></li>');
subUl.append(subLi);
if(t[2]!==true){
subLi.click(trigger,t[1]);
subLi.click(function () {ContextMenu._removeContextMenu();});
}
counterForTop++;
}
});
if(y+dom.height()>document.body.clientHeight && document.body.clientHeight>0){
subMenu.css('top','-'+(counterForTop*30)+'px')
}
}
else if(typeof(item[1])==='function' &&item[2]!==true){
sub.click(trigger,item[1]);
sub.click(function () {ContextMenu._removeContextMenu();});
}
}
});
//修正坐标
if(y+dom.height()>document.body.clientHeight && document.body.clientHeight>0){y-=dom.height()}
dom.css({
top:y,
left:x,
});
},
_removeContextMenu:function () {
$('.'+ContextMenu._className).remove();
},
};
$(document).click(function (e) {
if ($(e.target).hasClass(ContextMenu._className) || $(e.target).parents('.'+ContextMenu._className).length > 0) return;
ContextMenu._removeContextMenu();
});