@imcyk/context-menu
Version:
基于vue3+vite+ts的右键菜单组件,适用于组合式api和选项式api。
2 lines (1 loc) • 12.9 kB
JavaScript
(function(t,b){typeof exports=="object"&&typeof module<"u"?module.exports=b(require("vue")):typeof define=="function"&&define.amd?define(["vue"],b):(t=typeof globalThis<"u"?globalThis:t||self,t["context-menu"]=b(t.Vue))})(this,function(t){"use strict";let b=null;const J=e=>{b==null||b.closeMenu(),b=e},K=e=>{b=null};process.env.NODE_ENV!=="production"&&Object.freeze({}),process.env.NODE_ENV!=="production"&&Object.freeze([]);const Q=()=>{},Z=Object.assign,ee=Array.isArray,te=e=>typeof e=="function",ne=e=>typeof e=="symbol";let oe;function se(e,n=oe){n&&n.active&&n.effects.push(e)}const j=e=>{const n=new Set(e);return n.w=0,n.n=0,n},P=e=>(e.w&w)>0,z=e=>(e.n&w)>0,le=({deps:e})=>{if(e.length)for(let n=0;n<e.length;n++)e[n].w|=w},ie=e=>{const{deps:n}=e;if(n.length){let s=0;for(let o=0;o<n.length;o++){const l=n[o];P(l)&&!z(l)?l.delete(e):n[s++]=l,l.w&=~w,l.n&=~w}n.length=s}};let S=0,w=1;const D=30;let f;Symbol(process.env.NODE_ENV!=="production"?"iterate":""),Symbol(process.env.NODE_ENV!=="production"?"Map key iterate":"");class ce{constructor(n,s=null,o){this.fn=n,this.scheduler=s,this.active=!0,this.deps=[],this.parent=void 0,se(this,o)}run(){if(!this.active)return this.fn();let n=f,s=H;for(;n;){if(n===this)return;n=n.parent}try{return this.parent=f,f=this,H=!0,w=1<<++S,S<=D?le(this):$(this),this.fn()}finally{S<=D&&ie(this),w=1<<--S,f=this.parent,H=s,this.parent=void 0,this.deferStop&&this.stop()}}stop(){f===this?this.deferStop=!0:this.active&&($(this),this.onStop&&this.onStop(),this.active=!1)}}function $(e){const{deps:n}=e;if(n.length){for(let s=0;s<n.length;s++)n[s].delete(e);n.length=0}}let H=!0;function A(e,n){let s=!1;S<=D?z(e)||(e.n|=w,s=!P(e)):s=!e.has(f),s&&(e.add(f),f.deps.push(e),process.env.NODE_ENV!=="production"&&f.onTrack&&f.onTrack(Object.assign({effect:f},n)))}function R(e,n){const s=ee(e)?e:[...e];for(const o of s)o.computed&&F(o,n);for(const o of s)o.computed||F(o,n)}function F(e,n){(e!==f||e.allowRecurse)&&(process.env.NODE_ENV!=="production"&&e.onTrigger&&e.onTrigger(Z({effect:e},n)),e.scheduler?e.scheduler():e.run())}new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(ne));function V(e){const n=e&&e.__v_raw;return n?V(n):e}function ae(e){H&&f&&(e=V(e),process.env.NODE_ENV!=="production"?A(e.dep||(e.dep=j()),{target:e,type:"get",key:"value"}):A(e.dep||(e.dep=j())))}function re(e,n){e=V(e),e.dep&&(process.env.NODE_ENV!=="production"?R(e.dep,{target:e,type:"set",key:"value",newValue:n}):R(e.dep))}var L;class de{constructor(n,s,o,l){this._setter=s,this.dep=void 0,this.__v_isRef=!0,this[L]=!1,this._dirty=!0,this.effect=new ce(n,()=>{this._dirty||(this._dirty=!0,re(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!l,this.__v_isReadonly=o}get value(){const n=V(this);return ae(n),(n._dirty||!n._cacheable)&&(n._dirty=!1,n._value=n.effect.run()),n._value}set value(n){this._setter(n)}}L="__v_isReadonly";function fe(e,n,s=!1){let o,l;const r=te(e);r?(o=e,l=process.env.NODE_ENV!=="production"?()=>{console.warn("Write operation failed: computed value is readonly")}:Q):(o=e.get,l=e.set);const d=new de(o,l,r||!l,s);return process.env.NODE_ENV!=="production"&&n&&!s&&(d.effect.onTrack=n.onTrack,d.effect.onTrigger=n.onTrigger),d}const ue={class:"icon"},me={key:0,class:"label"},he={name:"i-context-menu-item"},pe=t.defineComponent({...he,props:{disabled:{type:Boolean,default:!1},customComponent:null,customClass:{default:""},label:{default:""},icon:{default:""},iconFontClass:{default:"iconfont"},showRightArrow:{type:Boolean,default:!1},clickClose:{type:Boolean,default:!0},clickableWhenHasChildren:{type:Boolean,default:!1},clickHandler:{type:Function,default:()=>{}},metadata:{default:()=>({})}},setup(e){const n=e,s=t.useSlots(),o=t.ref(!1),l=t.inject("menuContext"),r=t.inject("globalNamespace"),d=t.inject("globalFrom"),W=t.inject("globalCloseMenu"),g=t.inject("globalOptions"),y=()=>{l.checkCloseOtherSubMenuTimeOut()||l.closeOtherSubMenu(),l.addOpenedSubMenu(()=>{o.value=!1}),o.value=!0},k=fe(()=>{const u={disabled:n.disabled,label:n.label,icon:n.icon,iconFontClass:n.iconFontClass,showRightArrow:n.showRightArrow,clickClose:n.clickClose,clickableWhenHasChildren:n.clickableWhenHasChildren,metadata:n.metadata};return d&&(u.from=d),u}),E=()=>{n.disabled||(s.submenu?n.clickableWhenHasChildren&&typeof n.clickHandler=="function"&&n.clickHandler(n.metadata,k.value):(typeof n.clickHandler=="function"&&n.clickHandler(n.metadata,k.value),n.clickClose&&W()))};return(u,C)=>(t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass([t.unref(r)+"context-menu-item",e.disabled?"disabled":"",e.customClass]),onClick:E,onMouseenter:y},[e.customComponent?(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.customComponent),{key:1,data:t.unref(k)},null,8,["data"])):(t.openBlock(),t.createElementBlock(t.Fragment,{key:0},[t.createElementVNode("div",ue,[typeof e.icon=="string"?(t.openBlock(),t.createElementBlock("i",{key:0,class:t.normalizeClass([e.icon,e.iconFontClass])},null,2)):(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.icon),{key:1,data:t.unref(k)},null,8,["data"]))]),typeof e.label=="string"?(t.openBlock(),t.createElementBlock("span",me,t.toDisplayString(e.label),1)):(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.label),{key:1,data:t.unref(k)},null,8,["data"])),e.showRightArrow?(t.openBlock(),t.createElementBlock(t.Fragment,{key:2},[typeof(t.unref(g).moreArrow||"")=="string"?(t.openBlock(),t.createElementBlock("div",{key:0,class:t.normalizeClass(["right-arrow","more",t.unref(g).moreArrow])},null,2)):(t.openBlock(),t.createBlock(t.resolveDynamicComponent(t.unref(g).moreArrow),{key:1,data:{...t.unref(k),className:["right-arrow","more"]}},null,8,["data"]))],64)):t.createCommentVNode("",!0)],64)),o.value?t.renderSlot(u.$slots,"submenu",{key:2}):t.createCommentVNode("",!0)],34))}});var ye=/^\d+((px)|%)?$/;function v(e){let n=e.offsetTop;return e.offsetParent!=null&&(n-=e.offsetParent.scrollTop,n+=v(e.offsetParent)),n}function I(e){let n=e.offsetLeft;return e.offsetParent!=null&&(n-=e.offsetParent.scrollLeft,n+=I(e.offsetParent)),n}const U=e=>ye.test(String(e)),ke={key:0,class:"divided"},be=[t.createElementVNode("div",{class:"double-arrow"},null,-1)],ge=[t.createElementVNode("div",{class:"double-arrow"},null,-1)],Ce={name:"i-context-menu-sub"},xe=t.defineComponent({...Ce,props:{items:null,maxWidth:null,minWidth:null,adjustPosition:{type:Boolean,default:!0}},setup(e){const n=e,s=3,o=document.body.clientHeight,l=document.body.clientWidth;let r=0;const d=t.inject("globalOptions"),W=t.inject("menuContext"),g=t.inject("globalNamespace"),{zIndex:y,getMyPosition:k,getParentWidth:E}=W,u=t.ref(!1),C=t.ref(0),m=t.ref(0),O=[],x=t.ref({x:0,y:0}),h=t.ref(),N=t.ref(),X=t.ref(),Se={zIndex:y+1,getMyPosition:()=>{const a={x:0,y:0};return h.value&&(a.x=h.value.offsetWidth+(d.xOffset||0)),d.yOffset&&(a.y=d.yOffset),a},getParentWidth:()=>{var a;return(a=h.value)==null?void 0:a.offsetWidth},addOpenedSubMenu(a){O.push(a)},closeOtherSubMenu(){O.forEach(a=>a()),O.splice(0,O.length)},checkCloseOtherSubMenuTimeOut(){return r?(clearTimeout(r),r=0,!0):!1},closeOtherSubMenuWithTimeOut(){r=setTimeout(()=>{r=0,this.closeOtherSubMenu()},200)}},Y=a=>{var p,_,c,B;let i=0;a=="down"?i=Math.max(C.value-50,-m.value):i=Math.min(C.value+50,0),i>0&&(i=0),i<Number((p=N.value)==null?void 0:p.offsetHeight)-Number((_=h.value)==null?void 0:_.offsetHeight)&&(i=Number((c=N.value)==null?void 0:c.offsetHeight)-Number((B=h.value)==null?void 0:B.offsetHeight)),C.value=i},Oe=t.computed(()=>{const a=o*.95,i=o*.8,p=(d==null?void 0:d.maxHeight)||0;return{maxWidth:n.maxWidth?U(n.maxWidth)?n.maxWidth:n.maxWidth+"px":"",minWidth:n.minWidth?U(n.minWidth)?n.minWidth:n.minWidth+"px":"",maxHeight:(i>p?i:a>p&&p!=0?p:a)+"px",zIndex:y,left:`${x.value.x}px`,top:`${x.value.y}px`}});return t.provide("menuContext",Se),t.onMounted(()=>{x.value=k(),t.nextTick(()=>{const a=h.value,i=N.value;if(!a||!i)return!1;if(n.adjustPosition&&h.value&&X.value){m.value=a.offsetHeight-(i==null?void 0:i.offsetHeight),u.value=a.offsetHeight>(i==null?void 0:i.offsetHeight);const p=I(a),_=v(i);p+a.offsetWidth-l>0?x.value.x-=(E?E():0)+a.offsetWidth-s:x.value.x-=s;const B=_+i.offsetHeight-o;B>0&&(x.value.y-=B*1.05)}})}),(a,i)=>{var _;const p=t.resolveComponent("i-context-menu-sub");return t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass([t.unref(g)+"context-menu-sub",((_=t.unref(d))==null?void 0:_.customClass)||""]),style:t.normalizeStyle(t.unref(Oe)),onContextmenu:i[2]||(i[2]=t.withModifiers(()=>{},["stop","prevent"])),ref_key:"sub",ref:N},[t.createElementVNode("div",{class:t.normalizeClass([t.unref(g)+"context-menu-sub-body"]),ref_key:"menu",ref:h,style:t.normalizeStyle({top:`${C.value}px`})},[e.items?(t.openBlock(!0),t.createElementBlock(t.Fragment,{key:0},t.renderList(e.items,(c,B)=>(t.openBlock(),t.createElementBlock("div",{key:B},[t.createVNode(pe,{clickHandler:c.onClick,disabled:c.disabled,iconFontClass:t.unref(d).iconFontClass,icon:c.icon,label:c.label,customComponent:c.customComponent,customClass:c.customClass,clickClose:c.clickClose,clickableWhenHasChildren:c.clickableWhenHasChildren,showRightArrow:c.children&&c.children.length>0,metadata:c.metadata||{}},t.createSlots({_:2},[c.children&&c.children.length>0?{name:"submenu",fn:t.withCtx(()=>[t.createVNode(p,{items:c.children,maxWidth:c.maxWidth,minWidth:c.minWidth,adjustPosition:c.adjustSubMenuPosition},null,8,["items","maxWidth","minWidth","adjustPosition"])]),key:"0"}:void 0]),1032,["clickHandler","disabled","iconFontClass","icon","label","customComponent","customClass","clickClose","clickableWhenHasChildren","showRightArrow","metadata"]),c.divided?(t.openBlock(),t.createElementBlock("div",ke)):t.createCommentVNode("",!0)]))),128)):t.createCommentVNode("",!0)],6),t.createElementVNode("div",{class:t.normalizeClass([t.unref(g)+"context-menu-scroll"]),ref_key:"scroll",ref:X},[t.withDirectives(t.createElementVNode("div",{class:"updown up",onClick:i[0]||(i[0]=c=>Y("up"))},be,512),[[t.vShow,u.value&&C.value<0]]),t.withDirectives(t.createElementVNode("div",{class:"updown down",onClick:i[1]||(i[1]=c=>Y("down"))},ge,512),[[t.vShow,u.value&&C.value>-m.value]])],2)],38)}}}),we={name:"i-context-menu"},Ee=t.defineComponent({...we,props:{options:null,namespace:null,from:{default:""}},emits:["close"],setup(e,{expose:n,emit:s}){const o=e,l=t.ref("context-menu-host"),r=t.ref(!0),d={zIndex:(o.options||{}).zIndex||100,getMyPosition:()=>({x:o.options.x,y:o.options.y}),addOpenedSubMenu:()=>{},closeOtherSubMenu:()=>{}},W=()=>{document.removeEventListener("click",u,!0),document.removeEventListener("contextmenu",u,!0),document.removeEventListener("wheel",E,!0)},g=()=>{document.addEventListener("click",u,!0),document.addEventListener("contextmenu",u,!0),document.addEventListener("wheel",E,!0)},y=()=>{r.value=!1,s("close"),K()},k=m=>{for(;m;){if(m.classList&&m.classList.contains(l.value))return!1;m=m.parentNode}W(),y()},E=()=>{o.options.closeWhenScroll!==!1&&y()};function u(m){k(m.target)}const C=()=>{J({closeMenu:y})};return t.provide("globalOptions",o.options),t.provide("globalNamespace",o.namespace||""),t.provide("globalFrom",o.from),t.provide("globalCloseMenu",y),t.provide("menuContext",d),C(),t.onMounted(()=>{g()}),t.onUnmounted(()=>{W()}),n({closeMenu:y}),(m,O)=>{var x,h,N;return r.value?(t.openBlock(),t.createElementBlock("div",{key:0,class:t.normalizeClass([e.namespace+"context-menu",l.value,e.options.customClass])},[t.createVNode(xe,{items:(x=e.options)==null?void 0:x.items,"max-width":(h=e.options)==null?void 0:h.maxWidth,"min-width":(N=e.options)==null?void 0:N.minWidth},null,8,["items","max-width","min-width"]),t.renderSlot(m.$slots,"default")],2)):t.createCommentVNode("",!0)}}}),Te="",Ne={prefix:"",alias:"",namespace:""};let T={};const _e=({options:e,namespace:n,from:s},o,l)=>{const r=t.h(Ee,{options:e,namespace:n,from:s,onClose:()=>{t.render(null,o)}},l);return t.render(r,o),document.body.appendChild(o.firstElementChild),r.component},q=e=>Array.isArray(e)?{items:e}:e&&typeof e=="object"?e:{},Be=e=>e.replace(/[_-]+[a-zA-z]/g,n=>n.substr(-1).toUpperCase()),M=(e,n,s)=>{const{namespace:o}=T,l=document.createElement("div");return _e({options:e,namespace:o?o+"-":"",from:s||""},l,n)},G=(e,n)=>{e.preventDefault();const{value:s,arg:o="default"}=n;if(s&&typeof s=="object")M({...q(s),x:e.x,y:e.y});else{const l=s||"",{globalMenus:r={}}=T;M({...q(r[o]),x:e.x,y:e.y},void 0,l)}},Me=(e,n)=>{e.directive(n,{mounted:(s,o)=>{s.addEventListener("contextmenu",l=>G(l,o))},beforeMount:s=>{s.removeEventListener("contextmenu",G)}})},We=(e,n)=>{e.provide(n,M),e.config.globalProperties["$"+n]=M};return{install:(e,n)=>{T={...Ne,...n};const{prefix:s,alias:o}=T,l=o||Be([s||"","context","menu"].filter(r=>r&&r.trim()).join("-"));e.provide(l,M),e.config.globalProperties["$"+l]=M,We(e,l),Me(e,l)}}});