UNPKG

dragable-js

Version:

一个简单易用的js拖动库

2 lines (1 loc) 6.24 kB
(function(){"use strict";(function(){const dragStateMap=new WeakMap;const defaultOptions={dockable:true,dockDistance:20,dockAnimationDuration:300,dockAreas:["top","right","bottom","left"]};function initDragState(element,options){dragStateMap.set(element,{isDragging:false,startX:0,startY:0,startLeft:0,startTop:0,touchId:null,options:{...defaultOptions,...options},originalTransition:element.style.transition,originalPosition:window.getComputedStyle(element).position})}function checkAndDock(element,left,top){const state=dragStateMap.get(element);if(!state||!state.options.dockable)return{left:left,top:top,docked:false};const viewportWidth=window.innerWidth;const viewportHeight=window.innerHeight;const elementWidth=element.offsetWidth;const elementHeight=element.offsetHeight;const dockDistance=state.options.dockDistance;let newLeft=left;let newTop=top;let docked=false;let dockArea=null;if(state.options.dockAreas.includes("top")&&top<=dockDistance){newTop=0;docked=true;dockArea="top"}else if(state.options.dockAreas.includes("bottom")&&top+elementHeight>=viewportHeight-dockDistance){newTop=viewportHeight-elementHeight;docked=true;dockArea="bottom"}if(state.options.dockAreas.includes("left")&&left<=dockDistance){newLeft=0;docked=true;dockArea=dockArea?`${dockArea}-left`:"left"}else if(state.options.dockAreas.includes("right")&&left+elementWidth>=viewportWidth-dockDistance){newLeft=viewportWidth-elementWidth;docked=true;dockArea=dockArea?`${dockArea}-right`:"right"}if(docked){element.style.transition=`left ${state.options.dockAnimationDuration}ms ease-out, top ${state.options.dockAnimationDuration}ms ease-out`;const event=new CustomEvent("dock",{detail:{area:dockArea,left:newLeft,top:newTop}});element.dispatchEvent(event)}return{left:newLeft,top:newTop,docked:docked,dockArea:dockArea}}function handleDragStart(element,e){const state=dragStateMap.get(element);if(!state)return;e.preventDefault();element.style.transition=state.originalTransition;let clientX,clientY;if(e.type.includes("touch")){const touch=e.touches[0]||e.changedTouches[0];clientX=touch.clientX;clientY=touch.clientY;state.touchId=touch.identifier}else{clientX=e.clientX;clientY=e.clientY}const style=window.getComputedStyle(element);const left=parseFloat(style.left)||0;const top=parseFloat(style.top)||0;state.isDragging=true;state.startX=clientX;state.startY=clientY;state.startLeft=left;state.startTop=top;element.classList.add("dragging");const event=new CustomEvent("dragstart",{detail:{x:clientX,y:clientY}});element.dispatchEvent(event)}function handleDragMove(element,e){const state=dragStateMap.get(element);if(!state||!state.isDragging)return;e.preventDefault();let clientX,clientY;if(e.type.includes("touch")){let touch;if(e.touches){for(let i=0;i<e.touches.length;i++){if(e.touches[i].identifier===state.touchId){touch=e.touches[i];break}}}if(!touch&&e.changedTouches){for(let i=0;i<e.changedTouches.length;i++){if(e.changedTouches[i].identifier===state.touchId){touch=e.changedTouches[i];break}}}if(!touch)return;clientX=touch.clientX;clientY=touch.clientY}else{clientX=e.clientX;clientY=e.clientY}const deltaX=clientX-state.startX;const deltaY=clientY-state.startY;let newLeft=state.startLeft+deltaX;let newTop=state.startTop+deltaY;const viewportWidth=window.innerWidth;const viewportHeight=window.innerHeight;const elementWidth=element.offsetWidth;const elementHeight=element.offsetHeight;newLeft=Math.max(0,Math.min(newLeft,viewportWidth-elementWidth));newTop=Math.max(0,Math.min(newTop,viewportHeight-elementHeight));const dockResult=checkAndDock(element,newLeft,newTop);element.style.left=`${dockResult.left}px`;element.style.top=`${dockResult.top}px`;const event=new CustomEvent("dragmove",{detail:{x:clientX,y:clientY,left:dockResult.left,top:dockResult.top,docked:dockResult.docked,dockArea:dockResult.dockArea}});element.dispatchEvent(event)}function handleDragEnd(element,e){const state=dragStateMap.get(element);if(!state||!state.isDragging)return;e.preventDefault();state.isDragging=false;element.classList.remove("dragging");setTimeout(()=>{element.style.transition=state.originalTransition},state.options.dockAnimationDuration);const event=new CustomEvent("dragend");element.dispatchEvent(event)}HTMLElement.prototype.enableDrag=function(options){const computedStyle=window.getComputedStyle(this);if(computedStyle.position==="static"){this.style.position="absolute"}initDragState(this,options);this.addEventListener("mousedown",this._dragStartHandler=e=>handleDragStart(this,e));this.addEventListener("touchstart",this._dragStartHandlerTouch=e=>handleDragStart(this,e),{passive:false});document.addEventListener("mousemove",this._dragMoveHandler=e=>handleDragMove(this,e));document.addEventListener("touchmove",this._dragMoveHandlerTouch=e=>handleDragMove(this,e),{passive:false});document.addEventListener("mouseup",this._dragEndHandler=e=>handleDragEnd(this,e));document.addEventListener("touchend",this._dragEndHandlerTouch=e=>handleDragEnd(this,e));document.addEventListener("touchcancel",this._dragEndHandlerTouchCancel=e=>handleDragEnd(this,e))};HTMLElement.prototype.disableDrag=function(){if(this._dragStartHandler){this.removeEventListener("mousedown",this._dragStartHandler);this._dragStartHandler=null}if(this._dragStartHandlerTouch){this.removeEventListener("touchstart",this._dragStartHandlerTouch);this._dragStartHandlerTouch=null}if(this._dragMoveHandler){document.removeEventListener("mousemove",this._dragMoveHandler);this._dragMoveHandler=null}if(this._dragMoveHandlerTouch){document.removeEventListener("touchmove",this._dragMoveHandlerTouch);this._dragMoveHandlerTouch=null}if(this._dragEndHandler){document.removeEventListener("mouseup",this._dragEndHandler);this._dragEndHandler=null}if(this._dragEndHandlerTouch){document.removeEventListener("touchend",this._dragEndHandlerTouch);this._dragEndHandlerTouch=null}if(this._dragEndHandlerTouchCancel){document.removeEventListener("touchcancel",this._dragEndHandlerTouchCancel);this._dragEndHandlerTouchCancel=null}const state=dragStateMap.get(this);if(state){this.style.transition=state.originalTransition;if(state.originalPosition==="static"){this.style.position=state.originalPosition}}dragStateMap.delete(this);this.classList.remove("dragging")}})()})();