rightmenu
Version:
Right click menu
195 lines (181 loc) • 11.1 kB
JavaScript
export default {
// 调用use时候执行该方法
install: function (Vue, options) {
var GLOBLEsize = 0;
// 声明
Vue.directive("rightMenu", {
// 插入时候触发
bind(el, binding, vnode) {
// 设置body宽高(为了遮照)
document.body.style.position = "fixed";
document.body.style.width = "100%";
document.body.style.height = "100%";
// 防止id重复 每次累计加一
let currentSize = GLOBLEsize;
if (el.style.position == "") {
el.style.position = "relative";
}
// 设置菜单层级高于遮罩层
el.style.zIndex = "99998";
/**
* 增加一个遮罩层方便我控制菜单显示时候取消其余事件
*/
var Mask = document.createElement("div");
var Maskstyle = "position:fixed;top:0;left:0;width:100%;height:100%;z-index:99997;"
Mask.style = Maskstyle + "display:none";
Mask.setAttribute("id", "TT_MASK");
document.body.appendChild(Mask);
el.addEventListener("contextmenu", (e) => {
// debugger;
var e = event || window.event;
e.stopPropagation();//阻止冒泡事件
e.cancelBubble = true;//阻止冒泡事件ie
e.preventDefault();//阻止默认事件
// 隐藏所有菜单
for (let i = 0; i < GLOBLEsize; i++) {
if (document.getElementById("tt_right_menu" + i)) {
document.getElementById("tt_right_menu" + i).style = `display:none`
}
}
// 菜单位置
var menuX = e.pageX || e.pageY ? e.pageX : e.clientX + document.body.scrollLeft - document.body.clientLeft;//获取pageX 兼容ie
var menuY = e.pageX || e.pageY ? e.pageY : e.clientY + document.body.scrollTop - document.body.clientTop;
// 右键显示遮罩层
document.getElementById("TT_MASK").style = Maskstyle + "display:block";
// 找不到这个节点时候 新增一个menu 用于多个菜单的兼容问题
if (!document.getElementById("tt_right_menu" + currentSize)) {
// 创建div
let boxDiv = document.createElement("div");
// 指令的绑定值进行遍历 生成菜单的节点
binding.value["menus"].map((item) => {
let optionp = document.createElement("div");
// 控制icon位置
let iconPosition = "";
// icon内容
let icon = "";
// 文字内容
let content = "";
// 设置节点文字不可选中
optionp.setAttribute("unselectable", "on");
/**
* 兼容用户没有callback的情况
*/
if (item.callback) {
optionp.onclick = function(){
// 隐藏菜单的父级节点
optionp.parentNode.style.display = "none";
// 隐藏遮罩层
Mask.style = Maskstyle + "display:none";
return vnode.context[item.callback](item);
}
} else {
// 无callback情况
optionp.onclick = function () {
// 隐藏菜单的父级节点
optionp.parentNode.style.display = "none";
// 隐藏遮罩层
Mask.style = Maskstyle + "display:none";
return false;
}
}
/**
* 兼容在展开的选项上右击会出现默认右键,以及禁用穿透事件
*/
optionp.addEventListener("contextmenu", (e) => {
var e = event || window.event;
e.stopPropagation();//阻止冒泡事件
e.cancelBubble = true;//阻止冒泡事件ie
e.preventDefault();//阻止默认事件
})
// 如果用户设置了icon
if(item.icon){
// 判断icon位置是左还是右面 -》 可扩展为一个函数 让用户更高程度自定义
if(item.iconPosition && (item.iconPosition == "left" || item.iconPosition == "right")){
iconPosition = item.iconPosition
}else{
// 默认值 left
iconPosition = "left";
}
icon = item.icon;
}
// 判断content文字 也可以升级为一个函数提高可扩展性
if (item.content) {
content = item.content;
}
// 判断icon是否有
if(icon != ""){
// 剧左或者右
if(iconPosition == "right"){
// 生成img
let img = new Image();
img.src = icon;
img.style = (item.iconStyle || "")+"vertical-align:middle;";
optionp.innerHTML = content;
// 追加到option
optionp.appendChild(img);
}else{
let img = new Image();
img.src = icon;
img.style = (item.iconStyle || "")+"vertical-align:middle;";
optionp.appendChild(img);
optionp.innerHTML += content;
}
}else{
// 设置文字内容
optionp.innerHTML = content;
}
/**
* 兼容屏幕出界的情况;
*/
optionp.style = `text-align:center;overflow: hidden;text-overflow:ellipsis;white-space:nowrap;margin-block-start: 0em;margin-block-end: 0em;-webkit-touch-callout: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;${binding.value["optionStyle"] ? binding.value["optionStyle"] : ""};${item["style"] ? item["style"] : ""};`
// 追加选项到总菜单
boxDiv.appendChild(optionp);
})
// 设置唯一id
boxDiv.setAttribute("id", "tt_right_menu" + currentSize);
// 菜单的样式
boxDiv.style = `background:#fff;color:#333;${binding.value["boxStyle"] ? binding.value["boxStyle"] : ""};position:fixed;z-index:99999;top:${menuY}px;left:${menuX}px;`
// 追加到页面
document.body.appendChild(boxDiv);
let divWidth = boxDiv.clientWidth || boxDiv.offsetWidth;
} else {
// 节点已经存在则不需要重复创建 节省性能,只需要获取后设置位置即可
let boxDiv = document.getElementById("tt_right_menu" + currentSize);
boxDiv.style = `color:#333;background:#fff;${binding.value["boxStyle"] ? binding.value["boxStyle"] : ""};position:fixed;z-index:99999;top:${menuY}px;left:${menuX}px;`
/**
* 判断是否超出屏幕宽度
*/
if (menuX + boxDiv.clientWidth >= document.body.clientWidth) {
boxDiv.style.left = menuX - boxDiv.clientWidth + "px";
}
/**
* 判断是否超出屏幕高度
*/
if (menuY + boxDiv.clientHeight >= document.body.clientHeight) {
boxDiv.style.top = menuY - boxDiv.clientHeight + "px";
}
}
})
// 每次创建都会使得唯一遍量增加 防止重复
GLOBLEsize++;
// 增加遮罩层的点击事件 (在空白处点击移除右键菜单)-》包含左键和右键点击
document.getElementById("TT_MASK").addEventListener("click", () => {
if (document.getElementById("tt_right_menu" + currentSize)) {
document.getElementById("tt_right_menu" + currentSize).style = `display:none`
}
document.getElementById("TT_MASK").style = "display:none";
})
document.getElementById("TT_MASK").addEventListener("contextmenu", () => {
if (document.getElementById("tt_right_menu" + currentSize)) {
document.getElementById("tt_right_menu" + currentSize).style = `display:none`
}
document.getElementById("TT_MASK").style = "display:none";
})
},
unbind(el) {
// 解绑时候移除右键监听防止影响其他页面
el.removeEventListener("contextmenu",this,true);
}
})
}
}