拖拽代码:
"use strict";
;(() => {
const isFunction = (fn) => {
return typeof fn === 'function';
}
const isObject = (o) => {
return typeof o === 'object';
}
const isString = (str) => {
return typeof str === 'string';
}
const isArray = (arr) => {
return Object.prototype.toString.call(arr) === '[object Array]';
}
const isPC = () => {
return !navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
}
const getEl = (el) => {
return !el ? null : ( isString(el) ? document.querySelector(el) : el);
}
const getStyle = (ele) => {
var style = null;
if(window.getComputedStyle) {
style = window.getComputedStyle(ele, null);
}else{
style = ele.currentStyle;
}
return style;
}
const addEvent = (el, type, cb, capture = false ) => {
if( isString(type) ) {
el.addEventListener(type || 'click', cb, capture);
} else if (isArray(type)) {
type.map(event => addEvent(el, event, cb, capture));
}
}
const removeEvent = (el, type, cb, capture = false) => {
if( isString(type) ) {
el.removeEventListener(type || 'click', cb, capture);
} else if (isArray(type)) {
type.map(event => removeEvent(el, event, cb, capture));
}
}
const initEvent = ['touchstart', 'mousedown', 'touchend', 'mouseup'];
const moveEvent = ['touchmove', 'mousemove', 'mouseup'];
class DragEvent {
constructor(el, event) {
if( !el ) return;
const {top, left, width, height} = el.getBoundingClientRect();
this.t = top;
this.l = left;
this.w = width;
this.h = height;
this.el = el;
if( event ) {
this.time = new Date().getTime();
this.event = event;
this.setPoint(event);
}
}
get Page() {
const event = this.event;
const { pageX, pageY } = isPC() ? event : event.touches[0];
return {pageX, pageY};
}
setPoint() {
this.pointX = this.Page.pageX;
this.pointY = this.Page.pageY;
}
}
class _Drag {
static zIndex = 1;
constructor(options, cb) {
let el = null, wrap = document.body;
if( !options ) return false;
if ( isObject(options) ) {
if (options.nodeType === 1) {
el = options;
} else {
const {el: oel, wrap: oWrap} = options;
el = oel || null;
wrap = oWrap || wrap;
}
}
this.el = getEl(el);
const zIndex = Number(getStyle(this.el).zIndex);
_Drag.zIndex = (zIndex && zIndex > _Drag.zIndex) ? zIndex : _Drag.zIndex;
this.wrapNode = getEl(wrap);
this.cb = cb;
this.startDrag = null;
this.endDrag = null;
this.moveDrag = null;
this.wrap = new DragEvent(this.wrapNode);
this.init();
}
get moveTarget() {
return document;
}
handleEvent(e) {
const isPc = isPC();
const Build = isPc ? {
mousedown: this.start,
mousemove: this.move,
mouseup: this.end,
mouseout: this.end
} : {
touchstart: this.start,
touchmove: this.move,
touchend: this.end,
}
if( e.type && Build[e.type]) Build[e.type].call(this, e);
}
render(dragEvent) {
const { l, t } = dragEvent;
this.el.style.top = t + 'px';
this.el.style.left = l + 'px';
}
start(e) {
const { el, cb : { startCb } } = this;
const Event = new DragEvent(el, e);
_Drag.zIndex += 1;
el.style.zIndex = _Drag.zIndex;
el.style.position = 'fixed';
addEvent( this.moveTarget, moveEvent, this);
this.startDrag = Event;
this.moveDrag = Event;
this.render(Event);
startCb(Event);
}
move(event) {
const {cb : { moveCb }, startDrag: start, wrap } = this;
const { pageX, pageY } = isPC() ? event : event.touches[0];
let l = pageX - (start.pointX - start.l),
t = pageY - (start.pointY - start.t);
if ( l <= wrap.l ) l = wrap.l;
if ( l >= (wrap.l + wrap.w - start.w)) l = wrap.l + wrap.w - start.w;
if ( t <= wrap.t ) t = wrap.t;
if ( t >= (wrap.t + wrap.h - start.h) ) t = wrap.t + wrap.h - start.h;
let ld = (l - this.moveDrag.l),
td = (t - this.moveDrag.t);
ld = ld > 0 ? 1 : (ld < 0 ? -1 : ld);
td = td > 0 ? 1 : (td < 0 ? -1 : td);
Object.assign(this.moveDrag, { l, t, ld, td, pointX : pageX, pointY : pageY });
this.render(this.moveDrag);
event.preventDefault();
moveCb(this.moveDrag);
}
end(e) {
const { el, cb: { endCb } } = this;
removeEvent(this.moveTarget, moveEvent, this);
this.endDrag = new DragEvent(el, e);
endCb(this.endDrag);
}
init() {
const { el } = this;
addEvent(el, initEvent, this);
}
destory() {
removeEvent(el, initEvent, this);
}
}
class Drag {
constructor(...options) {
this.startList = [];
this.moveList = [];
this.endList = [];
this.drag = new _Drag(...options, {
startCb: o => this.fnCb('startList', o),
moveCb: o => this.fnCb('moveList', o),
endCb: o => this.fnCb('endList', o),
});
}
fnCb(type, o) {
this[type].map(item => item(o));
}
start(cb) {
if( isFunction(cb) ) this.startList.push(cb);
}
move(cb) {
if( isFunction(cb) ) this.moveList.push(cb);
}
end(cb) {
if( isFunction(cb) ) this.endList.push(cb);
}
}
window.Drag = Drag;
if(typeof module === 'object' && module.export) module.export = Drag;
})(window);
如何调用:
<html>
<style>
body {
border: 1px solid grey;
margin: 40px;
padding: 20px;
}
div:nth-of-type(odd){
border: 1px solid green;
}
div:nth-of-type(even) {
border: 1px solid yellow;
}
.item {
width: 100px;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
background: red;
}
</style>
<body>
<div id="item" class="item" >
哈哈
</div>
<div id="xixi" class="item">嘻嘻嘻</div>
</body>
<script src="./drag.js"></script>
<script type="text/javascript">
const el = document.querySelector('#item');
const xixi = document.querySelector('#xixi');
new Drag(xixi);
const drag = new Drag(el);
//支持绑定多个事件
drag.start((e) => {
// console.log('out-start:', e);
});
drag.start((e) => {
// console.log('out-start:', e);
});
drag.move((e) => {
// console.log('out-move: ', e.ld);
});
drag.end(() => {
// console.log('out-end');
});
</script>
</html>