UNPKG

self-right-menus

Version:

这是一个基于Vue的自定义右键无限层级菜单项目

161 lines (152 loc) 6.92 kB
import rightComponent from "./components/right.vue" const rightClick={}; /* 改写typeof 无法区分object array null 的缺陷 */ const _typeof=function(val){ let str= Object.prototype.toString.call(val).slice(8,-1); return str.toLowerCase(); } /* Vue.use(plugins) 如果插件是一个对象,必须提供 install 方法。 如果插件是一个函数,它会被作为 install 方法。 install 方法调用时,会将 Vue 作为参数传入 */ let menuVM=null; //是否已经显示自定义右键 let showMenu=null; let id=1; /** * 将组件挂在到节点上 * @param comp 需要挂载的组件 * @param prop 向组件传的参数 */ const creatComp = function(Vue,comp, prop) { // 创建组件 const app = Vue.extend(comp); // 创建一个div元素 const divEle = document.createElement("div"); // 将创建的div元素挂载追加至body里 document.body.appendChild(divEle); // 将组件挂载至刚才创建的div中, 使用propsData进行传参 let T=new app({ propsData: { ...prop } }).$mount(); // 返回挂载的元素,便于操作 divEle.appendChild(T.$el) return divEle; }; rightClick.install=(Vue)=>{ // 监听全局点击,销毁右键菜单dom document.body.addEventListener("click", () => { if (menuVM != null) { // 销毁右键菜单DOM document.body.removeChild(menuVM); menuVM = null; } }); // 监听全局右键点击,销毁右键菜单dom document.body.addEventListener('contextmenu',(e)=>{ //通过比较当前点击元素与右键自定义挂载元素是否一致;判断是否隐藏还是显示 let isSame=e===showMenu; if (menuVM != null&&!isSame) { //销毁右键菜单DOM document.body.removeChild(menuVM); menuVM = null; } }); Vue.directive('rightMenu',(el,binding)=>{ // 指令绑定元素元素是否存在判断 if (el == null) { throw "右键指令错误:元素未绑定"; } el.oncontextmenu = function(e) { showMenu=e; if (menuVM != null) { // 销毁上次触发的右键菜单DOM document.body.removeChild(menuVM); menuVM = null; } let obj=binding.value; if(!obj){ throw "右键指令错误:传值必须是对象"; } let width=binding.value.width; const textArray = binding.value.content; if(!Array.isArray(textArray)){ throw "右键指令错误:指令内容content必须为数组"; } //合成菜单项的内容并追加右键菜单数据及事件 function menus(textArray,dataArray,func){ /* 判断传入的右键菜单项是否有break字段; 如果没有:默认每三个打断; 如果有且break等于true按照break的位置打断 */ let isBreak=textArray.some(item=>{ return item.break }) for(let i=0;i<textArray.length;i++){ id=id+1; // 右键菜单对象, 添加名称 let menuObj = { text: textArray[i].label, handler:_typeof(textArray[i].handler) ==='function'?textArray[i].handler:false, id: id, disabled:textArray[i].disabled?textArray[i].disabled:false, }; if(isBreak){ menuObj.break=textArray[i].break?textArray[i].break:false; }else{ menuObj.break=(i+1)%3===0?true:false; } if(_typeof(textArray[i].children) ==='object'){ menuObj.children=func(textArray[i].children) }else{ menuObj.children=false; } dataArray.push(menuObj); } } // 处理好的右键菜单 const menuList = []; function appendChildMenus(children){ if(_typeof(children)==='object'){ let data={ rightMenuList:[], width:children.width?children.width:166, show:false, } let textArray=children.content; if(_typeof(textArray)==='array'&&textArray.length>0){ menus(textArray,data.rightMenuList,appendChildMenus) return data; }else{ return false } }else{ return false ; } } // 追加右键菜单数据及事件 menus(textArray,menuList,appendChildMenus) // 鼠标点的坐标 const oX = e.clientX; const oY = e.clientY; // 右键菜单出现后的位置 // 动态挂载组件,显示右键菜单 console.log(menuList) menuVM = creatComp(Vue,rightComponent, { rightMenuStatus: "block", rightMenuTop: oY + "px", rightMenuLeft: oX + "px", width:width?width:166, rightMenuList: menuList, }); return false; }; }) } export default rightClick