sortable-dnd
Advanced tools
Comparing version 0.0.12 to 0.1.0
/*! | ||
* sortable-dnd v0.0.12 | ||
* sortable-dnd v0.1.0 | ||
* open source under the MIT license | ||
@@ -89,2 +89,4 @@ * https://github.com/mfuu/sortable-dnd#readme | ||
var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i); | ||
var IOS = userAgent(/iP(ad|od|hone)/i); | ||
var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i); | ||
@@ -97,2 +99,18 @@ var captureMode = { | ||
/** | ||
* detect passive event support | ||
*/ | ||
function supportPassive() { | ||
// https://github.com/Modernizr/Modernizr/issues/1894 | ||
var supportPassive = false; | ||
document.addEventListener('checkIfSupportPassive', null, { | ||
get passive() { | ||
supportPassive = true; | ||
return true; | ||
} | ||
}); | ||
return supportPassive; | ||
} | ||
/** | ||
* add specified event listener | ||
@@ -102,9 +120,10 @@ * @param {HTMLElement} el | ||
* @param {Function} fn | ||
* @param {Boolean} sp | ||
*/ | ||
function on(el, event, fn) { | ||
function on(el, event, fn, sp) { | ||
if (window.addEventListener) { | ||
el.addEventListener(event, fn, !IE11OrLess && captureMode); | ||
el.addEventListener(event, fn, sp || !IE11OrLess ? captureMode : false); | ||
} else if (window.attachEvent) { | ||
el.addEventListener('on' + event, fn); | ||
el.attachEvent('on' + event, fn); | ||
} | ||
@@ -117,7 +136,8 @@ } | ||
* @param {Function} fn | ||
* @param {Boolean} sp | ||
*/ | ||
function off(el, event, fn) { | ||
function off(el, event, fn, sp) { | ||
if (window.removeEventListener) { | ||
el.removeEventListener(event, fn, !IE11OrLess && captureMode); | ||
el.removeEventListener(event, fn, sp || !IE11OrLess ? captureMode : false); | ||
} else if (window.detachEvent) { | ||
@@ -351,16 +371,2 @@ el.detachEvent('on' + event, fn); | ||
} | ||
function debounce(fn, delay) { | ||
return function () { | ||
var _this = this; | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
clearTimeout(fn.id); | ||
fn.id = setTimeout(function () { | ||
fn.call.apply(fn, [_this].concat(args)); | ||
}, delay); | ||
}; | ||
} | ||
function _nextTick(fn) { | ||
@@ -370,2 +376,4 @@ return setTimeout(fn, 0); | ||
var CSS_TRANSITIONS = ['-webkit-transition', '-moz-transition', '-ms-transition', '-o-transition', 'transition']; | ||
var CSS_TRANSFORMS = ['-webkit-transform', '-moz-transform', '-ms-transform', '-o-transform', 'transform']; | ||
function Animation() { | ||
@@ -405,12 +413,24 @@ var animationState = []; | ||
var top = preRect.top - curRect.top; | ||
css(el, 'transition', 'none'); | ||
css(el, 'transform', "translate3d(".concat(left, "px, ").concat(top, "px, 0)")); | ||
CSS_TRANSITIONS.forEach(function (ts) { | ||
return css(el, ts, 'none'); | ||
}); | ||
CSS_TRANSFORMS.forEach(function (tf) { | ||
return css(el, tf, "".concat(tf.split('transform')[0], "translate3d(").concat(left, "px, ").concat(top, "px, 0)")); | ||
}); | ||
el.offsetLeft; // 触发重绘 | ||
css(el, 'transition', "all ".concat(animation, "ms")); | ||
css(el, 'transform', 'translate3d(0px, 0px, 0px)'); | ||
CSS_TRANSITIONS.forEach(function (ts) { | ||
return css(el, ts, "".concat(ts.split('transition')[0], "transform ").concat(animation, "ms")); | ||
}); | ||
CSS_TRANSFORMS.forEach(function (tf) { | ||
return css(el, tf, "".concat(tf.split('transform')[0], "translate3d(0px, 0px, 0px)")); | ||
}); | ||
clearTimeout(el.animated); | ||
el.animated = setTimeout(function () { | ||
css(el, 'transition', ''); | ||
css(el, 'transform', ''); | ||
CSS_TRANSITIONS.forEach(function (ts) { | ||
return css(el, ts, ''); | ||
}); | ||
CSS_TRANSFORMS.forEach(function (tf) { | ||
return css(el, tf, ''); | ||
}); | ||
el.animated = null; | ||
@@ -434,2 +454,77 @@ }, animation); | ||
function DNDEvent() { | ||
return { | ||
_bindEventListener: function _bindEventListener() { | ||
this._onStart = this._onStart.bind(this); | ||
this._onMove = this._onMove.bind(this); | ||
this._onDrop = this._onDrop.bind(this); | ||
var _this$options = this.options, | ||
supportPointer = _this$options.supportPointer, | ||
supportTouch = _this$options.supportTouch, | ||
supportPassive = _this$options.supportPassive; | ||
if (supportPointer) { | ||
on(this.$el, 'pointerdown', this._onStart, supportPassive); | ||
} else if (supportTouch) { | ||
on(this.$el, 'touchstart', this._onStart, supportPassive); | ||
} else { | ||
on(this.$el, 'mousedown', this._onStart, supportPassive); | ||
} | ||
}, | ||
_unbindEventListener: function _unbindEventListener() { | ||
var supportPassive = this.options.supportPassive; | ||
off(this.$el, 'pointerdown', this._onStart, supportPassive); | ||
off(this.$el, 'touchstart', this._onStart, supportPassive); | ||
off(this.$el, 'mousedown', this._onStart, supportPassive); | ||
if (this.nativeDraggable) { | ||
off(this.$el, 'dragover', this); | ||
off(this.$el, 'dragenter', this); | ||
} | ||
}, | ||
_onMoveEvents: function _onMoveEvents(touch) { | ||
var _this$options2 = this.options, | ||
supportPointer = _this$options2.supportPointer, | ||
ownerDocument = _this$options2.ownerDocument, | ||
supportPassive = _this$options2.supportPassive; | ||
if (supportPointer) { | ||
on(ownerDocument, 'pointermove', this._onMove, supportPassive); | ||
} else if (touch) { | ||
on(ownerDocument, 'touchmove', this._onMove, supportPassive); | ||
} else { | ||
on(ownerDocument, 'mousemove', this._onMove, supportPassive); | ||
} | ||
}, | ||
_onUpEvents: function _onUpEvents() { | ||
var _this$options3 = this.options, | ||
ownerDocument = _this$options3.ownerDocument, | ||
supportPassive = _this$options3.supportPassive; | ||
on(ownerDocument, 'pointerup', this._onDrop, supportPassive); | ||
on(ownerDocument, 'pointercancel', this._onDrop, supportPassive); | ||
on(ownerDocument, 'touchend', this._onDrop, supportPassive); | ||
on(ownerDocument, 'touchcancel', this._onDrop, supportPassive); | ||
on(ownerDocument, 'mouseup', this._onDrop, supportPassive); | ||
}, | ||
_offMoveEvents: function _offMoveEvents() { | ||
var _this$options4 = this.options, | ||
ownerDocument = _this$options4.ownerDocument, | ||
supportPassive = _this$options4.supportPassive; | ||
off(ownerDocument, 'pointermove', this._onMove, supportPassive); | ||
off(ownerDocument, 'touchmove', this._onMove, supportPassive); | ||
off(ownerDocument, 'mousemove', this._onMove, supportPassive); | ||
}, | ||
_offUpEvents: function _offUpEvents() { | ||
var _this$options5 = this.options, | ||
ownerDocument = _this$options5.ownerDocument, | ||
supportPassive = _this$options5.supportPassive; | ||
off(ownerDocument, 'pointerup', this._onDrop, supportPassive); | ||
off(ownerDocument, 'pointercancel', this._onDrop, supportPassive); | ||
off(ownerDocument, 'touchend', this._onDrop, supportPassive); | ||
off(ownerDocument, 'touchcancel', this._onDrop, supportPassive); | ||
off(ownerDocument, 'mouseup', this._onDrop, supportPassive); | ||
} | ||
}; | ||
} | ||
/** | ||
@@ -520,6 +615,4 @@ * 拖拽前后差异初始化 | ||
this.$el.style.pointerEvents = 'none'; | ||
for (var key in ghostStyle) { | ||
css(this.$el, key, ghostStyle[key]); | ||
} | ||
this.$el.style.cursor = 'move'; | ||
this.setStyle(ghostStyle); | ||
} | ||
@@ -538,2 +631,9 @@ }, { | ||
}, { | ||
key: "setStyle", | ||
value: function setStyle(style) { | ||
for (var key in style) { | ||
css(this.$el, key, style[key]); | ||
} | ||
} | ||
}, { | ||
key: "rect", | ||
@@ -553,2 +653,3 @@ value: function rect() { | ||
this.$el.style.transform = "translate3d(".concat(this.x, "px, ").concat(this.y, "px, 0)"); | ||
if (this.$el.style.cursor !== 'move') this.$el.style.cursor = 'move'; | ||
} | ||
@@ -564,395 +665,348 @@ }, { | ||
return Ghost; | ||
}(); | ||
}(); // -------------------------------- Sortable ---------------------------------- | ||
var Sortable = /*#__PURE__*/function () { | ||
function Sortable(el, options) { | ||
_classCallCheck(this, Sortable); | ||
if (!el) throw new Error('container element is required'); | ||
this.$el = el; // 列表容器元素 | ||
var documentExists = typeof document !== 'undefined'; | ||
var supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'); | ||
/** | ||
* @class Sortable | ||
* @param {HTMLElement} el | ||
* @param {Object} options | ||
*/ | ||
this.options = options = Object.assign({}, options); | ||
this.scrollEl = getParentAutoScrollElement(this.$el, true); // 获取页面滚动元素 | ||
function Sortable(el, options) { | ||
if (!(el && el.nodeType && el.nodeType === 1)) { | ||
throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el)); | ||
} | ||
this.dragEl = null; // 拖拽元素 | ||
this.$el = el; // root element | ||
this.dropEl = null; // 释放元素 | ||
this.options = options = Object.assign({}, options); | ||
this.scrollEl = getParentAutoScrollElement(this.$el, true); // 获取页面滚动元素 | ||
this.differ = null; // 记录拖拽前后差异 | ||
this.dragEl = null; // 拖拽元素 | ||
this.ghost = null; // 拖拽时蒙版元素 | ||
this.dropEl = null; // 释放元素 | ||
this.calcXY = { | ||
x: 0, | ||
y: 0 | ||
}; // 记录拖拽移动时坐标 | ||
this.differ = null; // 记录拖拽前后差异 | ||
debounce(this.init(), 50); // 避免重复执行多次 | ||
} | ||
this.ghost = null; // 拖拽时蒙版元素 | ||
_createClass(Sortable, [{ | ||
key: "destroy", | ||
value: function destroy() { | ||
this._unbindEventListener(); | ||
this.calcXY = { | ||
x: 0, | ||
y: 0 | ||
}; // 记录拖拽移动时坐标 | ||
this._resetState(); | ||
} | ||
}, { | ||
key: "init", | ||
value: function init() { | ||
var defaults = { | ||
animation: 150, | ||
// 动画延时 | ||
ghostClass: '', | ||
ghostStyle: {}, | ||
chosenClass: '', | ||
draggable: undefined, | ||
// String: class, Function: (e) => return true | ||
dragging: null, | ||
// 必须为函数且必须返回一个 HTMLElement (e) => return e.target | ||
dragEnd: null, | ||
// 拖拽完成时的回调函数,返回两个值(olddom, newdom) => {} | ||
supportPointer: 'PointerEvent' in window && !Safari, | ||
ownerDocument: this.$el.ownerDocument | ||
}; // Set default options | ||
var defaults = { | ||
disabled: false, | ||
// | ||
animation: 150, | ||
// 动画延时 | ||
ghostClass: '', | ||
// 拖拽元素Class类名 | ||
ghostStyle: {}, | ||
// 拖拽元素样式 | ||
chosenClass: '', | ||
// 选中元素样式 | ||
draggable: undefined, | ||
// String: css selecter, Function: (e) => return true | ||
dragging: undefined, | ||
// 必须为函数且必须返回一个 HTMLElement: (e) => return e.target | ||
dragEnd: undefined, | ||
// 拖拽完成时的回调函数: (old, new, changed) => {} | ||
forceFallback: false, | ||
// 忽略 HTML5拖拽行为,强制回调进行 | ||
stopPropagation: false, | ||
// 阻止捕获和冒泡阶段中当前事件的进一步传播 | ||
supportPassive: supportPassive(), | ||
supportPointer: 'PointerEvent' in window && !Safari, | ||
supportTouch: 'ontouchstart' in window, | ||
ownerDocument: this.$el.ownerDocument | ||
}; // Set default options | ||
for (var name in defaults) { | ||
!(name in this.options) && (this.options[name] = defaults[name]); | ||
} | ||
for (var name in defaults) { | ||
!(name in this.options) && (this.options[name] = defaults[name]); | ||
} | ||
this.differ = new Differ(); | ||
this.ghost = new Ghost(this.options); | ||
Object.assign(this, Animation()); | ||
this.differ = new Differ(); | ||
this.ghost = new Ghost(this.options); | ||
Object.assign(this, Animation(), DNDEvent()); | ||
this._bindEventListener(); | ||
this._bindEventListener(); | ||
this._handleDestroy(); | ||
} // -------------------------------- drag and drop ---------------------------------- | ||
this.nativeDraggable = this.options.forceFallback ? false : supportDraggable; | ||
}, { | ||
key: "_onStart", | ||
value: function _onStart(evt) { | ||
var _this$options2 = this.options, | ||
dragging = _this$options2.dragging, | ||
draggable = _this$options2.draggable; | ||
var touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt; | ||
var e = touch || evt; | ||
if (this.nativeDraggable) { | ||
on(this.$el, 'dragover', this); | ||
on(this.$el, 'dragenter', this); | ||
} | ||
if (typeof draggable === 'function') { | ||
if (!draggable(e)) return true; | ||
} else if (typeof draggable === 'string') { | ||
if (!matches(e.target, draggable)) return true; | ||
} else if (draggable !== undefined) { | ||
throw new Error("draggable expected \"function\" or \"string\" but received \"".concat(_typeof(draggable), "\"")); | ||
} | ||
this._handleDestroy(); | ||
} | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0) return; // only left button and enabled | ||
Sortable.prototype = | ||
/** @lends Sortable.prototype */ | ||
{ | ||
constructor: Sortable, | ||
destroy: function destroy() { | ||
this._unbindEventListener(); | ||
if (e.target === this.$el) return true; | ||
this._resetState(); | ||
}, | ||
// -------------------------------- drag and drop ---------------------------------- | ||
_onStart: function _onStart( | ||
/** Event|TouchEvent */ | ||
evt) { | ||
var _this$options2 = this.options, | ||
disabled = _this$options2.disabled, | ||
dragging = _this$options2.dragging, | ||
draggable = _this$options2.draggable, | ||
stopPropagation = _this$options2.stopPropagation; | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0 || disabled) return; // only left button and enabled | ||
try { | ||
if (document.selection) { | ||
// Timeout neccessary for IE9 | ||
_nextTick(function () { | ||
document.selection.empty(); | ||
}); | ||
} else { | ||
window.getSelection().removeAllRanges(); | ||
} // 获取拖拽元素 | ||
var touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt; | ||
var e = touch || evt; // Safari ignores further event handling after mousedown | ||
if (!this.nativeDraggable && Safari && e.target && e.target.tagName.toUpperCase() === 'SELECT') return; | ||
if (e.target === this.$el) return true; | ||
var element = typeof dragging === 'function' ? dragging(e) : getElement(this.$el, e.target).el; // 不存在拖拽元素时不允许拖拽 | ||
if (typeof draggable === 'function') { | ||
if (!draggable(e)) return true; | ||
} else if (typeof draggable === 'string') { | ||
if (!matches(e.target, draggable)) return true; | ||
} else if (draggable !== undefined) { | ||
throw new Error("draggable expected \"function\" or \"string\" but received \"".concat(_typeof(draggable), "\"")); | ||
} | ||
if (!element) return true; | ||
if (element.animated) return; | ||
this.dragEl = element; | ||
} catch (error) { | ||
throw new Error(error); | ||
} | ||
if (evt.preventDefault !== void 0) evt.preventDefault(); | ||
if (stopPropagation) evt.stopPropagation(); | ||
window.sortableDndOnDown = true; // 获取当前元素在列表中的位置 | ||
try { | ||
if (document.selection) { | ||
// Timeout neccessary for IE9 | ||
_nextTick(function () { | ||
document.selection.empty(); | ||
}); | ||
} else { | ||
window.getSelection().removeAllRanges(); | ||
} // 获取拖拽元素 | ||
var _getElement = getElement(this.$el, this.dragEl), | ||
index = _getElement.index, | ||
el = _getElement.el, | ||
rect = _getElement.rect, | ||
offset = _getElement.offset; | ||
if (!el || index < 0) return true; // 将拖拽元素克隆一份作为蒙版 | ||
var element = typeof dragging === 'function' ? dragging(e) : getElement(this.$el, e.target).el; // 不存在拖拽元素时不允许拖拽 | ||
var ghostEl = this.dragEl.cloneNode(true); | ||
this.ghost.init(ghostEl, rect); | ||
this.ghost.set('x', rect.left); | ||
this.ghost.set('y', rect.top); | ||
this.differ._old_.rect = rect; | ||
this.differ._old_.offset = offset; | ||
this.differ._old_.node = this.dragEl; | ||
this.calcXY = { | ||
x: e.clientX, | ||
y: e.clientY | ||
}; | ||
this._onMoveEvents(touch); | ||
this._onUpEvents(touch); | ||
if (!element) return true; | ||
if (element.animated) return; | ||
this.dragEl = element; | ||
} catch (error) { | ||
throw new Error(error); | ||
} | ||
}, { | ||
key: "_onMove", | ||
value: function _onMove(evt) { | ||
evt.preventDefault(); | ||
var touch = evt.touches && evt.touches[0]; | ||
var e = touch || evt; | ||
var clientX = e.clientX, | ||
clientY = e.clientY; | ||
var target = touch ? document.elementFromPoint(clientX, clientY) : e.target; | ||
var chosenClass = this.options.chosenClass; | ||
toggleClass(this.dragEl, chosenClass, true); | ||
this.ghost.move(); | ||
if (!window.sortableDndOnDown) return; | ||
if (clientX < 0 || clientY < 0) return; | ||
document.body.style.cursor = 'grabbing'; | ||
window.sortableDndOnMove = true; | ||
this.ghost.set('x', this.ghost.x + clientX - this.calcXY.x); | ||
this.ghost.set('y', this.ghost.y + clientY - this.calcXY.y); | ||
this.calcXY = { | ||
x: clientX, | ||
y: clientY | ||
}; | ||
this.ghost.move(); | ||
var _getElement2 = getElement(this.$el, target), | ||
index = _getElement2.index, | ||
el = _getElement2.el, | ||
rect = _getElement2.rect, | ||
offset = _getElement2.offset; | ||
window.sortableDndOnDown = true; // 获取当前元素在列表中的位置 | ||
var left = rect.left, | ||
right = rect.right, | ||
top = rect.top, | ||
bottom = rect.bottom; | ||
if (!el || index < 0 || top < 0) return; // 判断边界值 | ||
var _getElement = getElement(this.$el, this.dragEl), | ||
index = _getElement.index, | ||
el = _getElement.el, | ||
rect = _getElement.rect, | ||
offset = _getElement.offset; | ||
var _rect = getRect(this.$el); | ||
if (!el || index < 0) return true; // 将拖拽元素克隆一份作为蒙版 | ||
this._checkRange(e, _rect); | ||
var ghostEl = this.dragEl.cloneNode(true); | ||
this.ghost.init(ghostEl, rect); | ||
this.ghost.set('x', rect.left); | ||
this.ghost.set('y', rect.top); | ||
this.differ._old_.rect = rect; | ||
this.differ._old_.offset = offset; | ||
this.differ._old_.node = this.dragEl; | ||
this.calcXY = { | ||
x: e.clientX, | ||
y: e.clientY | ||
}; | ||
var _this$scrollEl = this.scrollEl, | ||
scrollTop = _this$scrollEl.scrollTop, | ||
scrollLeft = _this$scrollEl.scrollLeft; // 如果目标元素超出当前可视区,不允许拖动 | ||
this._onMoveEvents(touch); | ||
if (this.scrollEl !== this.$el && (_rect.left < 0 || _rect.top < 0)) { | ||
if (rect.top < _rect.top + scrollTop && _rect.top < 0) return; | ||
if (rect.left < _rect.left + scrollLeft && _rect.left < 0) return; | ||
} else { | ||
if (rect.top < _rect.top) return; | ||
if (rect.left < _rect.left) return; | ||
} | ||
this._onUpEvents(touch); | ||
}, | ||
_onMove: function _onMove( | ||
/** Event|TouchEvent */ | ||
evt) { | ||
if (evt.preventDefault !== void 0) evt.preventDefault(); // prevent scrolling | ||
if (clientX > left && clientX < right && clientY > top && clientY < bottom) { | ||
this.dropEl = el; // 拖拽前后元素不一致时交换 | ||
var touch = evt.touches && evt.touches[0]; | ||
var e = touch || evt; | ||
var clientX = e.clientX, | ||
clientY = e.clientY; | ||
var target = touch ? document.elementFromPoint(clientX, clientY) : e.target; | ||
var _this$options3 = this.options, | ||
chosenClass = _this$options3.chosenClass, | ||
stopPropagation = _this$options3.stopPropagation; | ||
if (stopPropagation) evt.stopPropagation(); | ||
toggleClass(this.dragEl, chosenClass, true); | ||
this.ghost.move(); | ||
if (!window.sortableDndOnDown) return; | ||
if (clientX < 0 || clientY < 0) return; | ||
window.sortableDndOnMove = true; | ||
this.ghost.set('x', this.ghost.x + clientX - this.calcXY.x); | ||
this.ghost.set('y', this.ghost.y + clientY - this.calcXY.y); | ||
this.calcXY = { | ||
x: clientX, | ||
y: clientY | ||
}; | ||
this.ghost.move(); // 判断边界值 | ||
if (this.dropEl !== this.dragEl) { | ||
if (this.dropEl.animated) return; | ||
this.captureAnimationState(); | ||
var rc = getRect(this.$el); | ||
var _offset = getOffset(this.dragEl); // 获取拖拽元素的 offset 值 | ||
// 优先比较 top 值,top 值相同再比较 left | ||
if (clientX < rc.left || clientX > rc.right || clientY < rc.top || clientY > rc.bottom) { | ||
this.ghost.setStyle({ | ||
cursor: 'not-allowed' | ||
}); | ||
return; | ||
} | ||
var _getElement2 = getElement(this.$el, target), | ||
index = _getElement2.index, | ||
el = _getElement2.el, | ||
rect = _getElement2.rect, | ||
offset = _getElement2.offset; | ||
if (_offset.top < offset.top || _offset.left < offset.left) { | ||
this.$el.insertBefore(this.dragEl, this.dropEl.nextElementSibling); | ||
} else { | ||
this.$el.insertBefore(this.dragEl, this.dropEl); | ||
} | ||
var left = rect.left, | ||
right = rect.right, | ||
top = rect.top, | ||
bottom = rect.bottom; | ||
if (!el || index < 0 || top < 0) return; // 加上当前滚动距离 | ||
this.animateRange(); | ||
this.differ._new_.node = this.dropEl; | ||
this.differ._new_.rect = getRect(this.dropEl); | ||
} | ||
} | ||
} | ||
}, { | ||
key: "_onDrop", | ||
value: function _onDrop() { | ||
this._offMoveEvents(); | ||
var _this$scrollEl = this.scrollEl, | ||
scrollTop = _this$scrollEl.scrollTop, | ||
scrollLeft = _this$scrollEl.scrollLeft; | ||
var boundaryL = rc.left + scrollLeft; | ||
var boundaryT = rc.top + scrollTop; // 如果目标元素超出当前可视区,不允许拖动 | ||
this._offUpEvents(); | ||
if (this.scrollEl !== this.$el && (rc.left < 0 || rc.top < 0)) { | ||
if (rc.top < 0 && top < boundaryT || rc.left < 0 && left < boundaryL) return; | ||
} else if (top < rc.top || left < rc.left) return; | ||
document.body.style.cursor = ''; | ||
var _this$options3 = this.options, | ||
dragEnd = _this$options3.dragEnd, | ||
chosenClass = _this$options3.chosenClass; | ||
toggleClass(this.dragEl, chosenClass, false); | ||
if (clientX > left && clientX < right && clientY > top && clientY < bottom) { | ||
this.dropEl = el; // 拖拽前后元素不一致时交换 | ||
if (window.sortableDndOnDown && window.sortableDndOnMove) { | ||
// 重新获取一次拖拽元素的 offset 值作为拖拽完成后的 offset 值 | ||
this.differ._new_.offset = getOffset(this.dragEl); // 拖拽完成触发回调函数 | ||
if (this.dropEl !== this.dragEl) { | ||
if (this.dropEl.animated) return; | ||
this.captureAnimationState(); | ||
var _this$differ = this.differ, | ||
_old_ = _this$differ._old_, | ||
_new_ = _this$differ._new_; // 通过 offset 比较是否进行了元素交换 | ||
var _offset = getOffset(this.dragEl); // 获取拖拽元素的 offset 值 | ||
// 优先比较 top 值,top 值相同再比较 left | ||
var changed = _old_.offset.top !== _new_.offset.top || _old_.offset.left !== _new_.offset.left; // 如果拖拽前后没有发生交换,重新赋值一次 | ||
if (!changed) this.differ._new_.node = this.differ._old_.node; | ||
if (typeof dragEnd === 'function') { | ||
dragEnd(_old_, _new_, changed); | ||
if (_offset.top < offset.top || _offset.left < offset.left) { | ||
this.$el.insertBefore(this.dragEl, this.dropEl.nextElementSibling); | ||
} else { | ||
throw new Error("Sortable-dnd Error: dragEnd expected \"function\" but received \"".concat(_typeof(dragEnd), "\"")); | ||
this.$el.insertBefore(this.dragEl, this.dropEl); | ||
} | ||
this.animateRange(); | ||
this.differ._new_.node = this.dropEl; | ||
this.differ._new_.rect = getRect(this.dropEl); | ||
} | ||
} | ||
}, | ||
_onDrop: function _onDrop( | ||
/** Event|TouchEvent */ | ||
evt) { | ||
this._offMoveEvents(); | ||
this.differ.destroy(); | ||
this.ghost.destroy(); | ||
this._offUpEvents(); | ||
this._removeWindowState(); | ||
} | ||
}, { | ||
key: "_checkRange", | ||
value: function _checkRange(e, groupRect) { | ||
var top = groupRect.top, | ||
left = groupRect.left, | ||
right = groupRect.right, | ||
bottom = groupRect.bottom; | ||
var _this$options4 = this.options, | ||
dragEnd = _this$options4.dragEnd, | ||
chosenClass = _this$options4.chosenClass, | ||
stopPropagation = _this$options4.stopPropagation; | ||
if (stopPropagation) evt.stopPropagation(); // 阻止事件冒泡 | ||
if (e.clientX < left || e.clientX > right || e.clientY < top || e.clientY > bottom) { | ||
document.body.style.cursor = 'not-allowed'; | ||
return; | ||
} | ||
} // -------------------------------- auto destroy ---------------------------------- | ||
toggleClass(this.dragEl, chosenClass, false); | ||
}, { | ||
key: "_handleDestroy", | ||
value: function _handleDestroy() { | ||
var _this = this; | ||
if (window.sortableDndOnDown && window.sortableDndOnMove) { | ||
// 重新获取一次拖拽元素的 offset 值作为拖拽完成后的 offset 值 | ||
this.differ._new_.offset = getOffset(this.dragEl); // 拖拽完成触发回调函数 | ||
var observer = null; | ||
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; | ||
var _this$differ = this.differ, | ||
_old_ = _this$differ._old_, | ||
_new_ = _this$differ._new_; // 通过 offset 比较是否进行了元素交换 | ||
if (MutationObserver) { | ||
var ownerDocument = this.options.ownerDocument; | ||
observer = new MutationObserver(function () { | ||
if (!ownerDocument.body.contains(_this.$el)) { | ||
observer.disconnect(); | ||
observer = null; | ||
var changed = _old_.offset.top !== _new_.offset.top || _old_.offset.left !== _new_.offset.left; // 如果拖拽前后没有发生交换,重新赋值一次 | ||
_this._unbindEventListener(); | ||
if (!changed) this.differ._new_.node = this.differ._old_.node; | ||
_this._resetState(); | ||
} | ||
}); | ||
observer.observe(this.$el.parentNode, { | ||
childList: true, | ||
// 观察目标子节点的变化,是否有添加或者删除 | ||
attributes: false, | ||
// 观察属性变动 | ||
subtree: false // 观察后代节点,默认为 false | ||
}); | ||
if (typeof dragEnd === 'function') { | ||
dragEnd(_old_, _new_, changed); | ||
} else { | ||
throw new Error("Sortable-dnd Error: dragEnd expected \"function\" but received \"".concat(_typeof(dragEnd), "\"")); | ||
} | ||
} | ||
window.onbeforeunload = function () { | ||
if (observer) observer.disconnect(); | ||
observer = null; | ||
this.differ.destroy(); | ||
this.ghost.destroy(); | ||
_this._unbindEventListener(); | ||
this._removeWindowState(); | ||
}, | ||
// -------------------------------- auto destroy ---------------------------------- | ||
_handleDestroy: function _handleDestroy() { | ||
var _this = this; | ||
_this._resetState(); | ||
}; | ||
} // -------------------------------- reset state ---------------------------------- | ||
var observer = null; | ||
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; | ||
}, { | ||
key: "_resetState", | ||
value: function _resetState() { | ||
this.dragEl = null; | ||
this.dropEl = null; | ||
this.ghost.destroy(); | ||
this.differ.destroy(); | ||
this.calcXY = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
if (MutationObserver) { | ||
var ownerDocument = this.options.ownerDocument; | ||
if (!ownerDocument) return; | ||
observer = new MutationObserver(function () { | ||
if (!ownerDocument.body.contains(_this.$el)) { | ||
observer.disconnect(); | ||
observer = null; | ||
this._removeWindowState(); | ||
} | ||
}, { | ||
key: "_removeWindowState", | ||
value: function _removeWindowState() { | ||
window.sortableDndOnDown = null; | ||
window.sortableDndOnMove = null; | ||
delete window.sortableDndOnDown; | ||
delete window.sortableDndOnMove; | ||
} // -------------------------------- listener ---------------------------------- | ||
_this._unbindEventListener(); | ||
}, { | ||
key: "_bindEventListener", | ||
value: function _bindEventListener() { | ||
this._onStart = this._onStart.bind(this); | ||
this._onMove = this._onMove.bind(this); | ||
this._onDrop = this._onDrop.bind(this); | ||
var supportPointer = this.options.supportPointer; | ||
_this._resetState(); | ||
} | ||
}); | ||
observer.observe(this.$el.parentNode, { | ||
childList: true, | ||
// 观察目标子节点的变化,是否有添加或者删除 | ||
attributes: false, | ||
// 观察属性变动 | ||
subtree: false // 观察后代节点,默认为 false | ||
if (supportPointer) { | ||
on(this.$el, 'pointerdown', this._onStart); | ||
} else { | ||
on(this.$el, 'mousedown', this._onStart); | ||
on(this.$el, 'touchstart', this._onStart); | ||
} | ||
}); | ||
} | ||
}, { | ||
key: "_unbindEventListener", | ||
value: function _unbindEventListener() { | ||
off(this.$el, 'pointerdown', this._onStart); | ||
off(this.$el, 'touchstart', this._onStart); | ||
off(this.$el, 'mousedown', this._onStart); | ||
} | ||
}, { | ||
key: "_onMoveEvents", | ||
value: function _onMoveEvents(touch) { | ||
var _this$options4 = this.options, | ||
supportPointer = _this$options4.supportPointer, | ||
ownerDocument = _this$options4.ownerDocument; | ||
if (supportPointer) { | ||
on(ownerDocument, 'pointermove', this._onMove); | ||
} else if (touch) { | ||
on(ownerDocument, 'touchmove', this._onMove); | ||
} else { | ||
on(ownerDocument, 'mousemove', this._onMove); | ||
} | ||
} | ||
}, { | ||
key: "_onUpEvents", | ||
value: function _onUpEvents() { | ||
var ownerDocument = this.options.ownerDocument; | ||
on(ownerDocument, 'pointerup', this._onDrop); | ||
on(ownerDocument, 'touchend', this._onDrop); | ||
on(ownerDocument, 'touchcancel', this._onDrop); | ||
on(ownerDocument, 'mouseup', this._onDrop); | ||
} | ||
}, { | ||
key: "_offMoveEvents", | ||
value: function _offMoveEvents() { | ||
var ownerDocument = this.options.ownerDocument; | ||
off(ownerDocument, 'pointermove', this._onMove); | ||
off(ownerDocument, 'touchmove', this._onMove); | ||
off(ownerDocument, 'mousemove', this._onMove); | ||
} | ||
}, { | ||
key: "_offUpEvents", | ||
value: function _offUpEvents() { | ||
var ownerDocument = this.options.ownerDocument; | ||
off(ownerDocument, 'mouseup', this._onDrop); | ||
off(ownerDocument, 'touchend', this._onDrop); | ||
off(ownerDocument, 'touchcancel', this._onDrop); | ||
off(ownerDocument, 'pointerup', this._onDrop); | ||
} | ||
}]); | ||
window.onbeforeunload = function () { | ||
if (observer) observer.disconnect(); | ||
observer = null; | ||
return Sortable; | ||
}(); | ||
_this._unbindEventListener(); | ||
_this._resetState(); | ||
}; | ||
}, | ||
// -------------------------------- reset state ---------------------------------- | ||
_resetState: function _resetState() { | ||
this.dragEl = null; | ||
this.dropEl = null; | ||
this.ghost.destroy(); | ||
this.differ.destroy(); | ||
this.calcXY = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
this._removeWindowState(); | ||
}, | ||
_removeWindowState: function _removeWindowState() { | ||
window.sortableDndOnDown = null; | ||
window.sortableDndOnMove = null; | ||
delete window.sortableDndOnDown; | ||
delete window.sortableDndOnMove; | ||
} | ||
}; | ||
return Sortable; | ||
})); |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Sortable=e()}(this,function(){"use strict";function s(t){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function r(t,e,n){e&&i(t.prototype,e),n&&i(t,n),Object.defineProperty(t,"prototype",{writable:!1})}function l(t){return function(t){if(Array.isArray(t))return a(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return a(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Map"===(n="Object"===n&&t.constructor?t.constructor.name:n)||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?a(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var h=t(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),f=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),c={capture:!1,passive:!1},u=/\s+/g;function d(t,e,n){window.addEventListener?t.addEventListener(e,n,!h&&c):window.attachEvent&&t.addEventListener("on"+e,n)}function e(t,e,n){window.removeEventListener?t.removeEventListener(e,n,!h&&c):window.detachEvent&&t.detachEvent("on"+e,n)}function p(t){for(var e={top:0,left:0,height:0,width:0},n=(e.height=t.offsetHeight,e.width=t.offsetWidth,e.top=t.offsetTop,e.left=t.offsetLeft,t.offsetParent);null!==n;)e.top+=n.offsetTop,e.left+=n.offsetLeft,n=n.offsetParent;return e}function v(){var t=document.scrollingElement;return t||document.documentElement}function y(t){var e;if(t.getBoundingClientRect||t===window)return e={top:0,left:0,bottom:0,right:0,height:0,width:0},t!==window&&t.parentNode&&t!==v()?(t=t.getBoundingClientRect(),e.top=t.top,e.left=t.left,e.bottom=t.bottom,e.right=t.right,e.height=t.height,e.width=t.width):(e.top=0,e.left=0,e.bottom=window.innerHeight,e.right=window.innerWidth,e.height=window.innerHeight,e.width=window.innerWidth),e}function g(t,e){var n={index:-1,el:null,rect:{},offset:{}},o=l(Array.from(t.children)),t=o.indexOf(e);-1<t&&Object.assign(n,{index:t,el:o[t],rect:y(o[t]),offset:p(o[t])});for(var i=0;i<o.length;i++)if(function(t,e){var n;if(t&&e)for(n=t.parentNode;n;){if(e===n)return 1;n=n.parentNode}return}(e,o[i])){Object.assign(n,{index:i,el:o[i],rect:y(o[i]),offset:p(o[i])});break}return n}function w(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(u," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(u," ")))}function m(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=e in o||-1!==e.indexOf("webkit")?e:"-webkit-"+e]=n+("string"==typeof n?"":"px")}}function b(){var o=[];return{captureAnimationState:function(){var t=l(Array.from(this.$el.children)),e=function(t,e,n){e=t.indexOf(e),t=t.indexOf(n);return e<t?{start:e,end:t}:{start:t,end:e}}(t,this.dragEl,this.dropEl),n=e.start,e=e.end;o.length=0,t.slice(n,e+1).forEach(function(t){o.push({target:t,rect:y(t)})})},animateRange:function(){var n=this;o.forEach(function(t){var e=t.target,t=t.rect;n.animate(e,t,n.animation)})},animate:function(t,e){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:150,o=y(t),i=e.left-o.left,e=e.top-o.top;m(t,"transition","none"),m(t,"transform","translate3d(".concat(i,"px, ").concat(e,"px, 0)")),t.offsetLeft,m(t,"transition","all ".concat(n,"ms")),m(t,"transform","translate3d(0px, 0px, 0px)"),clearTimeout(t.animated),t.animated=setTimeout(function(){m(t,"transition",""),m(t,"transform",""),t.animated=null},n)}}}var _=function(){function t(){o(this,t),this._old_={node:null,rect:{},offset:{}},this._new_={node:null,rect:{},offset:{}}}return r(t,[{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e}},{key:"destroy",value:function(){this._old_={node:null,rect:{},offset:{}},this._new_={node:null,rect:{},offset:{}}}}]),t}(),E=function(){function e(t){o(this,e),this.options=t,this.x=0,this.y=0,this.exist=!1}return r(e,[{key:"init",value:function(t,e){if(t){this.$el=t;var n,t=this.options,o=t.ghostClass,t=t.ghostStyle,i=void 0===t?{}:t,t=e.width,e=e.height;for(n in this.$el.class=o,this.$el.style.width=t+"px",this.$el.style.height=e+"px",this.$el.style.transform="",this.$el.style.transition="",this.$el.style.position="fixed",this.$el.style.left=0,this.$el.style.top=0,this.$el.style.zIndex=1e5,this.$el.style.opacity=.8,this.$el.style.pointerEvents="none",i)m(this.$el,n,i[n])}}},{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e,this[t]=e}},{key:"rect",value:function(){return this.$el.getBoundingClientRect()}},{key:"move",value:function(){this.exist||(document.body.appendChild(this.$el),this.exist=!0),this.$el.style.transform="translate3d(".concat(this.x,"px, ").concat(this.y,"px, 0)")}},{key:"destroy",value:function(){this.$el&&this.$el.remove(),this.exist=!1}}]),e}();return function(){function n(t,e){if(o(this,n),!t)throw new Error("container element is required");this.$el=t,this.options=e=Object.assign({},e),this.scrollEl=function(t,e){if(!t||!t.getBoundingClientRect)return v();var n=t,o=!1;do{if(n.clientWidth<n.scrollWidth||n.clientHeight<n.scrollHeight){var i=m(n);if(n.clientWidth<n.scrollWidth&&("auto"==i.overflowX||"scroll"==i.overflowX)||n.clientHeight<n.scrollHeight&&("auto"==i.overflowY||"scroll"==i.overflowY)){if(!n.getBoundingClientRect||n===document.body)return v();if(o||e)return n;o=!0}}}while(n=n.parentNode);return v()}(this.$el,!0),this.dragEl=null,this.dropEl=null,this.differ=null,this.ghost=null,this.calcXY={x:0,y:0},this.init()}return r(n,[{key:"destroy",value:function(){this._unbindEventListener(),this._resetState()}},{key:"init",value:function(){var t,e={animation:150,ghostClass:"",ghostStyle:{},chosenClass:"",draggable:void 0,dragging:null,dragEnd:null,supportPointer:"PointerEvent"in window&&!f,ownerDocument:this.$el.ownerDocument};for(t in e)t in this.options||(this.options[t]=e[t]);this.differ=new _,this.ghost=new E(this.options),Object.assign(this,b()),this._bindEventListener(),this._handleDestroy()}},{key:"_onStart",value:function(t){var e=this.options,n=e.dragging,e=e.draggable,o=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,i=o||t;if("function"==typeof e){if(!e(i))return!0}else if("string"==typeof e){if(!function(t,e){if(e&&(">"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}(i.target,e))return!0}else if(void 0!==e)throw new Error('draggable expected "function" or "string" but received "'.concat(s(e),'"'));if(!/mousedown|pointerdown/.test(t.type)||0===t.button){if(i.target===this.$el)return!0;try{document.selection?setTimeout(function(){document.selection.empty()},0):window.getSelection().removeAllRanges();var r="function"==typeof n?n(i):g(this.$el,i.target).el;if(!r)return!0;if(r.animated)return;this.dragEl=r}catch(t){throw new Error(t)}window.sortableDndOnDown=!0;e=g(this.$el,this.dragEl),t=e.index,n=e.el,r=e.rect,e=e.offset;if(!n||t<0)return!0;n=this.dragEl.cloneNode(!0);this.ghost.init(n,r),this.ghost.set("x",r.left),this.ghost.set("y",r.top),this.differ._old_.rect=r,this.differ._old_.offset=e,this.differ._old_.node=this.dragEl,this.calcXY={x:i.clientX,y:i.clientY},this._onMoveEvents(o),this._onUpEvents(o)}}},{key:"_onMove",value:function(t){t.preventDefault();var e=t.touches&&t.touches[0],t=e||t,n=t.clientX,o=t.clientY,e=e?document.elementFromPoint(n,o):t.target,i=this.options.chosenClass;if(w(this.dragEl,i,!0),this.ghost.move(),window.sortableDndOnDown&&!(n<0||o<0)){document.body.style.cursor="grabbing",window.sortableDndOnMove=!0,this.ghost.set("x",this.ghost.x+n-this.calcXY.x),this.ghost.set("y",this.ghost.y+o-this.calcXY.y),this.calcXY={x:n,y:o},this.ghost.move();var i=g(this.$el,e),e=i.index,r=i.el,s=i.rect,i=i.offset,l=s.left,a=s.right,h=s.top,f=s.bottom;if(!(!r||e<0||h<0)){var e=y(this.$el),t=(this._checkRange(t,e),this.scrollEl),c=t.scrollTop,t=t.scrollLeft;if(this.scrollEl!==this.$el&&(e.left<0||e.top<0)){if(s.top<e.top+c&&e.top<0)return;if(s.left<e.left+t&&e.left<0)return}else{if(s.top<e.top)return;if(s.left<e.left)return}l<n&&n<a&&h<o&&o<f&&(this.dropEl=r,this.dropEl===this.dragEl||this.dropEl.animated||(this.captureAnimationState(),(c=p(this.dragEl)).top<i.top||c.left<i.left?this.$el.insertBefore(this.dragEl,this.dropEl.nextElementSibling):this.$el.insertBefore(this.dragEl,this.dropEl),this.animateRange(),this.differ._new_.node=this.dropEl,this.differ._new_.rect=y(this.dropEl)))}}}},{key:"_onDrop",value:function(){this._offMoveEvents(),this._offUpEvents(),document.body.style.cursor="";var t=this.options,e=t.dragEnd,t=t.chosenClass;if(w(this.dragEl,t,!1),window.sortableDndOnDown&&window.sortableDndOnMove){this.differ._new_.offset=p(this.dragEl);var t=this.differ,n=t._old_,t=t._new_,o=n.offset.top!==t.offset.top||n.offset.left!==t.offset.left;if(o||(this.differ._new_.node=this.differ._old_.node),"function"!=typeof e)throw new Error('Sortable-dnd Error: dragEnd expected "function" but received "'.concat(s(e),'"'));e(n,t,o)}this.differ.destroy(),this.ghost.destroy(),this._removeWindowState()}},{key:"_checkRange",value:function(t,e){var n=e.top,o=e.left,i=e.right,e=e.bottom;(t.clientX<o||t.clientX>i||t.clientY<n||t.clientY>e)&&(document.body.style.cursor="not-allowed")}},{key:"_handleDestroy",value:function(){var t,e=this,n=null,o=window.MutationObserver||window.WebKitMutationObserver;o&&(t=this.options.ownerDocument,(n=new o(function(){t.body.contains(e.$el)||(n.disconnect(),n=null,e._unbindEventListener(),e._resetState())})).observe(this.$el.parentNode,{childList:!0,attributes:!1,subtree:!1})),window.onbeforeunload=function(){n&&n.disconnect(),n=null,e._unbindEventListener(),e._resetState()}}},{key:"_resetState",value:function(){this.dragEl=null,this.dropEl=null,this.ghost.destroy(),this.differ.destroy(),this.calcXY={x:0,y:0},this._removeWindowState()}},{key:"_removeWindowState",value:function(){window.sortableDndOnDown=null,window.sortableDndOnMove=null,delete window.sortableDndOnDown,delete window.sortableDndOnMove}},{key:"_bindEventListener",value:function(){this._onStart=this._onStart.bind(this),this._onMove=this._onMove.bind(this),this._onDrop=this._onDrop.bind(this),this.options.supportPointer?d(this.$el,"pointerdown",this._onStart):(d(this.$el,"mousedown",this._onStart),d(this.$el,"touchstart",this._onStart))}},{key:"_unbindEventListener",value:function(){e(this.$el,"pointerdown",this._onStart),e(this.$el,"touchstart",this._onStart),e(this.$el,"mousedown",this._onStart)}},{key:"_onMoveEvents",value:function(t){var e=this.options,n=e.supportPointer,e=e.ownerDocument;d(e,n?"pointermove":t?"touchmove":"mousemove",this._onMove)}},{key:"_onUpEvents",value:function(){var t=this.options.ownerDocument;d(t,"pointerup",this._onDrop),d(t,"touchend",this._onDrop),d(t,"touchcancel",this._onDrop),d(t,"mouseup",this._onDrop)}},{key:"_offMoveEvents",value:function(){var t=this.options.ownerDocument;e(t,"pointermove",this._onMove),e(t,"touchmove",this._onMove),e(t,"mousemove",this._onMove)}},{key:"_offUpEvents",value:function(){var t=this.options.ownerDocument;e(t,"mouseup",this._onDrop),e(t,"touchend",this._onDrop),e(t,"touchcancel",this._onDrop),e(t,"pointerup",this._onDrop)}}]),n}()}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Sortable=e()}(this,function(){"use strict";function a(t){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function i(t,e,n){e&&o(t.prototype,e),n&&o(t,n),Object.defineProperty(t,"prototype",{writable:!1})}function r(t){return function(t){if(Array.isArray(t))return s(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return s(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Map"===(n="Object"===n&&t.constructor?t.constructor.name:n)||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?s(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function s(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var l=t(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),h=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),e=t(/iP(ad|od|hone)/i),f=t(/chrome/i)&&t(/android/i),c={capture:!1,passive:!1},u=/\s+/g;function d(t,e,n,o){window.addEventListener?t.addEventListener(e,n,!(!o&&l)&&c):window.attachEvent&&t.attachEvent("on"+e,n)}function p(t,e,n,o){window.removeEventListener?t.removeEventListener(e,n,!(!o&&l)&&c):window.detachEvent&&t.detachEvent("on"+e,n)}function v(t){for(var e={top:0,left:0,height:0,width:0},n=(e.height=t.offsetHeight,e.width=t.offsetWidth,e.top=t.offsetTop,e.left=t.offsetLeft,t.offsetParent);null!==n;)e.top+=n.offsetTop,e.left+=n.offsetLeft,n=n.offsetParent;return e}function g(){var t=document.scrollingElement;return t||document.documentElement}function m(t){var e;if(t.getBoundingClientRect||t===window)return e={top:0,left:0,bottom:0,right:0,height:0,width:0},t!==window&&t.parentNode&&t!==g()?(t=t.getBoundingClientRect(),e.top=t.top,e.left=t.left,e.bottom=t.bottom,e.right=t.right,e.height=t.height,e.width=t.width):(e.top=0,e.left=0,e.bottom=window.innerHeight,e.right=window.innerWidth,e.height=window.innerHeight,e.width=window.innerWidth),e}function w(t,e){var n={index:-1,el:null,rect:{},offset:{}},o=r(Array.from(t.children)),t=o.indexOf(e);-1<t&&Object.assign(n,{index:t,el:o[t],rect:m(o[t]),offset:v(o[t])});for(var i=0;i<o.length;i++)if(function(t,e){var n;if(t&&e)for(n=t.parentNode;n;){if(e===n)return 1;n=n.parentNode}return}(e,o[i])){Object.assign(n,{index:i,el:o[i],rect:m(o[i]),offset:v(o[i])});break}return n}function y(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(u," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(u," ")))}function b(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=e in o||-1!==e.indexOf("webkit")?e:"-webkit-"+e]=n+("string"==typeof n?"":"px")}}var _=["-webkit-transition","-moz-transition","-ms-transition","-o-transition","transition"],E=["-webkit-transform","-moz-transform","-ms-transform","-o-transform","transform"];function S(){var o=[];return{captureAnimationState:function(){var t=r(Array.from(this.$el.children)),e=function(t,e,n){e=t.indexOf(e),t=t.indexOf(n);return e<t?{start:e,end:t}:{start:t,end:e}}(t,this.dragEl,this.dropEl),n=e.start,e=e.end;o.length=0,t.slice(n,e+1).forEach(function(t){o.push({target:t,rect:m(t)})})},animateRange:function(){var n=this;o.forEach(function(t){var e=t.target,t=t.rect;n.animate(e,t,n.animation)})},animate:function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:150,o=m(e),i=t.left-o.left,r=t.top-o.top;_.forEach(function(t){return b(e,t,"none")}),E.forEach(function(t){return b(e,t,"".concat(t.split("transform")[0],"translate3d(").concat(i,"px, ").concat(r,"px, 0)"))}),e.offsetLeft,_.forEach(function(t){return b(e,t,"".concat(t.split("transition")[0],"transform ").concat(n,"ms"))}),E.forEach(function(t){return b(e,t,"".concat(t.split("transform")[0],"translate3d(0px, 0px, 0px)"))}),clearTimeout(e.animated),e.animated=setTimeout(function(){_.forEach(function(t){return b(e,t,"")}),E.forEach(function(t){return b(e,t,"")}),e.animated=null},n)}}}var D=function(){function t(){n(this,t),this._old_={node:null,rect:{},offset:{}},this._new_={node:null,rect:{},offset:{}}}return i(t,[{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e}},{key:"destroy",value:function(){this._old_={node:null,rect:{},offset:{}},this._new_={node:null,rect:{},offset:{}}}}]),t}(),$=function(){function e(t){n(this,e),this.options=t,this.x=0,this.y=0,this.exist=!1}return i(e,[{key:"init",value:function(t,e){var n,o;t&&(this.$el=t,n=(t=this.options).ghostClass,t=void 0===(t=t.ghostStyle)?{}:t,o=e.width,e=e.height,this.$el.class=n,this.$el.style.width=o+"px",this.$el.style.height=e+"px",this.$el.style.transform="",this.$el.style.transition="",this.$el.style.position="fixed",this.$el.style.left=0,this.$el.style.top=0,this.$el.style.zIndex=1e5,this.$el.style.opacity=.8,this.$el.style.pointerEvents="none",this.$el.style.cursor="move",this.setStyle(t))}},{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e,this[t]=e}},{key:"setStyle",value:function(t){for(var e in t)b(this.$el,e,t[e])}},{key:"rect",value:function(){return this.$el.getBoundingClientRect()}},{key:"move",value:function(){this.exist||(document.body.appendChild(this.$el),this.exist=!0),this.$el.style.transform="translate3d(".concat(this.x,"px, ").concat(this.y,"px, 0)"),"move"!==this.$el.style.cursor&&(this.$el.style.cursor="move")}},{key:"destroy",value:function(){this.$el&&this.$el.remove(),this.exist=!1}}]),e}(),x="undefined"!=typeof document&&!f&&!e&&"draggable"in document.createElement("div");function P(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.$el=t,this.options=e=Object.assign({},e),this.scrollEl=function(t,e){if(!t||!t.getBoundingClientRect)return g();var n=t,o=!1;do{if(n.clientWidth<n.scrollWidth||n.clientHeight<n.scrollHeight){var i=b(n);if(n.clientWidth<n.scrollWidth&&("auto"==i.overflowX||"scroll"==i.overflowX)||n.clientHeight<n.scrollHeight&&("auto"==i.overflowY||"scroll"==i.overflowY)){if(!n.getBoundingClientRect||n===document.body)return g();if(o||e)return n;o=!0}}}while(n=n.parentNode);return g()}(this.$el,!0),this.dragEl=null,this.dropEl=null,this.differ=null,this.ghost=null;var n,o,i={disabled:!(this.calcXY={x:0,y:0}),animation:150,ghostClass:"",ghostStyle:{},chosenClass:"",draggable:void 0,dragging:void 0,dragEnd:void 0,forceFallback:!1,stopPropagation:!1,supportPassive:(n=!1,document.addEventListener("checkIfSupportPassive",null,{get passive(){return n=!0}}),n),supportPointer:"PointerEvent"in window&&!h,supportTouch:"ontouchstart"in window,ownerDocument:this.$el.ownerDocument};for(o in i)o in this.options||(this.options[o]=i[o]);this.differ=new D,this.ghost=new $(this.options),Object.assign(this,S(),{_bindEventListener:function(){this._onStart=this._onStart.bind(this),this._onMove=this._onMove.bind(this),this._onDrop=this._onDrop.bind(this);var t=this.options,e=t.supportPointer,n=t.supportTouch,t=t.supportPassive;d(this.$el,e?"pointerdown":n?"touchstart":"mousedown",this._onStart,t)},_unbindEventListener:function(){var t=this.options.supportPassive;p(this.$el,"pointerdown",this._onStart,t),p(this.$el,"touchstart",this._onStart,t),p(this.$el,"mousedown",this._onStart,t),this.nativeDraggable&&(p(this.$el,"dragover",this),p(this.$el,"dragenter",this))},_onMoveEvents:function(t){var e=this.options,n=e.supportPointer,o=e.ownerDocument,e=e.supportPassive;d(o,n?"pointermove":t?"touchmove":"mousemove",this._onMove,e)},_onUpEvents:function(){var t=this.options,e=t.ownerDocument,t=t.supportPassive;d(e,"pointerup",this._onDrop,t),d(e,"pointercancel",this._onDrop,t),d(e,"touchend",this._onDrop,t),d(e,"touchcancel",this._onDrop,t),d(e,"mouseup",this._onDrop,t)},_offMoveEvents:function(){var t=this.options,e=t.ownerDocument,t=t.supportPassive;p(e,"pointermove",this._onMove,t),p(e,"touchmove",this._onMove,t),p(e,"mousemove",this._onMove,t)},_offUpEvents:function(){var t=this.options,e=t.ownerDocument,t=t.supportPassive;p(e,"pointerup",this._onDrop,t),p(e,"pointercancel",this._onDrop,t),p(e,"touchend",this._onDrop,t),p(e,"touchcancel",this._onDrop,t),p(e,"mouseup",this._onDrop,t)}}),this._bindEventListener(),this.nativeDraggable=!this.options.forceFallback&&x,this.nativeDraggable&&(d(this.$el,"dragover",this),d(this.$el,"dragenter",this)),this._handleDestroy()}return P.prototype={constructor:P,destroy:function(){this._unbindEventListener(),this._resetState()},_onStart:function(t){var e=this.options,n=e.disabled,o=e.dragging,i=e.draggable,e=e.stopPropagation;if(!(/mousedown|pointerdown/.test(t.type)&&0!==t.button||n)){var n=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,r=n||t;if(this.nativeDraggable||!h||!r.target||"SELECT"!==r.target.tagName.toUpperCase()){if(r.target===this.$el)return!0;if("function"==typeof i){if(!i(r))return!0}else if("string"==typeof i){if(!function(t,e){if(e&&(">"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}(r.target,i))return!0}else if(void 0!==i)throw new Error('draggable expected "function" or "string" but received "'.concat(a(i),'"'));void 0!==t.preventDefault&&t.preventDefault(),e&&t.stopPropagation();try{document.selection?setTimeout(function(){document.selection.empty()},0):window.getSelection().removeAllRanges();var s="function"==typeof o?o(r):w(this.$el,r.target).el;if(!s)return!0;if(s.animated)return;this.dragEl=s}catch(t){throw new Error(t)}window.sortableDndOnDown=!0;i=w(this.$el,this.dragEl),e=i.index,t=i.el,o=i.rect,s=i.offset;if(!t||e<0)return!0;i=this.dragEl.cloneNode(!0);this.ghost.init(i,o),this.ghost.set("x",o.left),this.ghost.set("y",o.top),this.differ._old_.rect=o,this.differ._old_.offset=s,this.differ._old_.node=this.dragEl,this.calcXY={x:r.clientX,y:r.clientY},this._onMoveEvents(n),this._onUpEvents(n)}}},_onMove:function(t){void 0!==t.preventDefault&&t.preventDefault();var e=t.touches&&t.touches[0],n=e||t,o=n.clientX,i=n.clientY,e=e?document.elementFromPoint(o,i):n.target,n=this.options,r=n.chosenClass,n=n.stopPropagation;if(n&&t.stopPropagation(),y(this.dragEl,r,!0),this.ghost.move(),window.sortableDndOnDown&&!(o<0||i<0)){window.sortableDndOnMove=!0,this.ghost.set("x",this.ghost.x+o-this.calcXY.x),this.ghost.set("y",this.ghost.y+i-this.calcXY.y),this.calcXY={x:o,y:i},this.ghost.move();n=m(this.$el);if(o<n.left||o>n.right||i<n.top||i>n.bottom)this.ghost.setStyle({cursor:"not-allowed"});else{var t=w(this.$el,e),r=t.index,e=t.el,s=t.rect,t=t.offset,a=s.left,l=s.right,h=s.top,s=s.bottom;if(!(!e||r<0||h<0)){var r=this.scrollEl,f=r.scrollTop,r=r.scrollLeft,r=n.left+r,f=n.top+f;if(this.scrollEl!==this.$el&&(n.left<0||n.top<0)){if(n.top<0&&h<f||n.left<0&&a<r)return}else if(h<n.top||a<n.left)return;a<o&&o<l&&h<i&&i<s&&(this.dropEl=e,this.dropEl===this.dragEl||this.dropEl.animated||(this.captureAnimationState(),(f=v(this.dragEl)).top<t.top||f.left<t.left?this.$el.insertBefore(this.dragEl,this.dropEl.nextElementSibling):this.$el.insertBefore(this.dragEl,this.dropEl),this.animateRange(),this.differ._new_.node=this.dropEl,this.differ._new_.rect=m(this.dropEl)))}}}},_onDrop:function(t){this._offMoveEvents(),this._offUpEvents();var e=this.options,n=e.dragEnd,o=e.chosenClass;if(e.stopPropagation&&t.stopPropagation(),y(this.dragEl,o,!1),window.sortableDndOnDown&&window.sortableDndOnMove){this.differ._new_.offset=v(this.dragEl);e=this.differ,t=e._old_,o=e._new_,e=t.offset.top!==o.offset.top||t.offset.left!==o.offset.left;if(e||(this.differ._new_.node=this.differ._old_.node),"function"!=typeof n)throw new Error('Sortable-dnd Error: dragEnd expected "function" but received "'.concat(a(n),'"'));n(t,o,e)}this.differ.destroy(),this.ghost.destroy(),this._removeWindowState()},_handleDestroy:function(){var t=this,e=null,n=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;if(n){var o=this.options.ownerDocument;if(!o)return;(e=new n(function(){o.body.contains(t.$el)||(e.disconnect(),e=null,t._unbindEventListener(),t._resetState())})).observe(this.$el.parentNode,{childList:!0,attributes:!1,subtree:!1})}window.onbeforeunload=function(){e&&e.disconnect(),e=null,t._unbindEventListener(),t._resetState()}},_resetState:function(){this.dragEl=null,this.dropEl=null,this.ghost.destroy(),this.differ.destroy(),this.calcXY={x:0,y:0},this._removeWindowState()},_removeWindowState:function(){window.sortableDndOnDown=null,window.sortableDndOnMove=null,delete window.sortableDndOnDown,delete window.sortableDndOnMove}},P}); |
{ | ||
"name": "sortable-dnd", | ||
"version": "0.0.12", | ||
"version": "0.1.0", | ||
"description": "JS Library for Drag and Drop, supports Sortable and Draggable", | ||
@@ -5,0 +5,0 @@ "main": "dist/sortable.js", |
@@ -49,3 +49,3 @@ <p> | ||
}, | ||
dragEnd: (old, new) => { | ||
dragEnd: (old, new, changed) => { | ||
... | ||
@@ -64,9 +64,12 @@ } | ||
|-------------|--------------|--------------|--------------| | ||
| `draggable` | `String/Function` | - | Specifies which items inside the element should be draggable, the function type must return a boolean | | ||
| `dragging` | `Function` | (e) => e.target | Specifies the drag and drop element, which must return an HTMLElement | | ||
| `dragEnd` | `Function` | (pre, cur, changed) => {} | The callback function when the drag is completed | | ||
| `ghostStyle` | `Object` | {} | The style of the mask element when dragging | | ||
| `ghostClass` | `String` | '' | The class of the mask element when dragging | | ||
| `chosenClass` | `String` | {} | The class of the selected element when dragging | | ||
| `animation` | `Number` | 150 | animation delay | | ||
| `disabled` | `Boolean` | `false` | Disables the sortable if set to true | | ||
| `draggable` | `String/Function` | `undefined` | Specifies which items inside the element should be draggable, the function type must return a boolean | | ||
| `dragging` | `Function` | `undefined` | Specifies the drag element, which must return an HTMLElement, such as `(e) => e.target` | | ||
| `dragEnd` | `Function` | `undefined` | The callback function when the drag is completed, such as `(old, new, changed) => {}` | | ||
| `ghostStyle` | `Object` | `{}` | The style of the mask element when dragging | | ||
| `ghostClass` | `String` | `''` | The class of the mask element when dragging | | ||
| `chosenClass` | `String` | `{}` | The class of the selected element when dragging | | ||
| `animation` | `Number` | `150` | animation delay | | ||
| `forceFallback` | `Boolean` | `false` | true: ignore the HTML5 DnD behaviour and force the fallback to kick in | | ||
| `stopPropagation` | `Boolean` | `false` | The `stopPropagation()` method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases | | ||
@@ -73,0 +76,0 @@ # Methods |
import { getRect, css } from './utils.js' | ||
const CSS_TRANSITIONS = ['-webkit-transition', '-moz-transition', '-ms-transition', '-o-transition', 'transition'] | ||
const CSS_TRANSFORMS = ['-webkit-transform', '-moz-transform', '-ms-transform', '-o-transform', 'transform'] | ||
export default function Animation() { | ||
@@ -34,14 +37,15 @@ | ||
const top = preRect.top - curRect.top | ||
css(el, 'transition', 'none') | ||
css(el, 'transform', `translate3d(${left}px, ${top}px, 0)`) | ||
CSS_TRANSITIONS.forEach(ts => css(el, ts, 'none')) | ||
CSS_TRANSFORMS.forEach(tf => css(el, tf, `${tf.split('transform')[0]}translate3d(${left}px, ${top}px, 0)`)) | ||
el.offsetLeft // 触发重绘 | ||
css(el, 'transition', `all ${animation}ms`) | ||
css(el, 'transform', 'translate3d(0px, 0px, 0px)') | ||
CSS_TRANSITIONS.forEach(ts => css(el, ts, `${ts.split('transition')[0]}transform ${animation}ms`)) | ||
CSS_TRANSFORMS.forEach(tf => css(el, tf, `${tf.split('transform')[0]}translate3d(0px, 0px, 0px)`)) | ||
clearTimeout(el.animated) | ||
el.animated = setTimeout(() => { | ||
css(el, 'transition', '') | ||
css(el, 'transform', '') | ||
CSS_TRANSITIONS.forEach(ts => css(el, ts, '')) | ||
CSS_TRANSFORMS.forEach(tf => css(el, tf, '')) | ||
el.animated = null | ||
@@ -48,0 +52,0 @@ }, animation) |
import { | ||
on, | ||
off, | ||
css, | ||
matches, | ||
getRect, | ||
debounce, | ||
getOffset, | ||
@@ -12,6 +10,8 @@ _nextTick, | ||
toggleClass, | ||
supportPassive, | ||
getParentAutoScrollElement | ||
} from './utils.js' | ||
import { Safari } from './Brower.js' | ||
import { IOS, Safari, ChromeForAndroid } from './Brower.js' | ||
import Animation from './Animation.js' | ||
import Events from './events.js' | ||
@@ -69,6 +69,5 @@ /** | ||
this.$el.style.pointerEvents = 'none' | ||
this.$el.style.cursor = 'move' | ||
for (const key in ghostStyle) { | ||
css(this.$el, key, ghostStyle[key]) | ||
} | ||
this.setStyle(ghostStyle) | ||
} | ||
@@ -85,2 +84,8 @@ | ||
setStyle(style) { | ||
for (const key in style) { | ||
css(this.$el, key, style[key]) | ||
} | ||
} | ||
rect() { | ||
@@ -97,2 +102,3 @@ return this.$el.getBoundingClientRect() | ||
this.$el.style.transform = `translate3d(${this.x}px, ${this.y}px, 0)` | ||
if (this.$el.style.cursor !== 'move') this.$el.style.cursor = 'move' | ||
} | ||
@@ -106,58 +112,92 @@ | ||
class Sortable { | ||
constructor(el, options) { | ||
if (!el) throw new Error('container element is required') | ||
// -------------------------------- Sortable ---------------------------------- | ||
this.$el = el // 列表容器元素 | ||
this.options = options = Object.assign({}, options) | ||
this.scrollEl = getParentAutoScrollElement(this.$el, true) // 获取页面滚动元素 | ||
const documentExists = typeof document !== 'undefined' | ||
const supportDraggable = documentExists && !ChromeForAndroid && !IOS && ('draggable' in document.createElement('div')) | ||
this.dragEl = null // 拖拽元素 | ||
this.dropEl = null // 释放元素 | ||
this.differ = null // 记录拖拽前后差异 | ||
this.ghost = null // 拖拽时蒙版元素 | ||
this.calcXY = { x: 0, y: 0 } // 记录拖拽移动时坐标 | ||
/** | ||
* @class Sortable | ||
* @param {HTMLElement} el | ||
* @param {Object} options | ||
*/ | ||
function Sortable(el, options) { | ||
if (!(el && el.nodeType && el.nodeType === 1)) { | ||
throw `Sortable: \`el\` must be an HTMLElement, not ${ {}.toString.call(el) }`; | ||
} | ||
debounce(this.init(), 50) // 避免重复执行多次 | ||
this.$el = el // root element | ||
this.options = options = Object.assign({}, options) | ||
this.scrollEl = getParentAutoScrollElement(this.$el, true) // 获取页面滚动元素 | ||
this.dragEl = null // 拖拽元素 | ||
this.dropEl = null // 释放元素 | ||
this.differ = null // 记录拖拽前后差异 | ||
this.ghost = null // 拖拽时蒙版元素 | ||
this.calcXY = { x: 0, y: 0 } // 记录拖拽移动时坐标 | ||
const defaults = { | ||
disabled: false, // | ||
animation: 150, // 动画延时 | ||
ghostClass: '', // 拖拽元素Class类名 | ||
ghostStyle: {}, // 拖拽元素样式 | ||
chosenClass: '', // 选中元素样式 | ||
draggable: undefined, // String: css selecter, Function: (e) => return true | ||
dragging: undefined, // 必须为函数且必须返回一个 HTMLElement: (e) => return e.target | ||
dragEnd: undefined, // 拖拽完成时的回调函数: (old, new, changed) => {} | ||
forceFallback: false, // 忽略 HTML5拖拽行为,强制回调进行 | ||
stopPropagation: false, // 阻止捕获和冒泡阶段中当前事件的进一步传播 | ||
supportPassive: supportPassive(), | ||
supportPointer: ('PointerEvent' in window) && !Safari, | ||
supportTouch: 'ontouchstart' in window, | ||
ownerDocument: this.$el.ownerDocument, | ||
} | ||
destroy() { | ||
this._unbindEventListener() | ||
this._resetState() | ||
// Set default options | ||
for (const name in defaults) { | ||
!(name in this.options) && (this.options[name] = defaults[name]) | ||
} | ||
init() { | ||
const defaults = { | ||
animation: 150, // 动画延时 | ||
this.differ = new Differ() | ||
this.ghost = new Ghost(this.options) | ||
ghostClass: '', | ||
ghostStyle: {}, | ||
chosenClass: '', | ||
draggable: undefined, // String: class, Function: (e) => return true | ||
dragging: null, // 必须为函数且必须返回一个 HTMLElement (e) => return e.target | ||
dragEnd: null, // 拖拽完成时的回调函数,返回两个值(olddom, newdom) => {} | ||
Object.assign(this, Animation(), Events()) | ||
supportPointer: ('PointerEvent' in window) && !Safari, | ||
ownerDocument: this.$el.ownerDocument, | ||
} | ||
// Set default options | ||
for (const name in defaults) { | ||
!(name in this.options) && (this.options[name] = defaults[name]) | ||
} | ||
this._bindEventListener() | ||
this.differ = new Differ() | ||
this.ghost = new Ghost(this.options) | ||
this.nativeDraggable = this.options.forceFallback ? false : supportDraggable | ||
Object.assign(this, Animation()) | ||
this._bindEventListener() | ||
this._handleDestroy() | ||
if (this.nativeDraggable) { | ||
on(this.$el, 'dragover', this) | ||
on(this.$el, 'dragenter', this) | ||
} | ||
this._handleDestroy() | ||
} | ||
Sortable.prototype = /** @lends Sortable.prototype */ { | ||
constructor: Sortable, | ||
destroy() { | ||
this._unbindEventListener() | ||
this._resetState() | ||
}, | ||
// -------------------------------- drag and drop ---------------------------------- | ||
_onStart(evt) { | ||
const { dragging, draggable } = this.options | ||
_onStart: function(/** Event|TouchEvent */evt) { | ||
const { disabled, dragging, draggable, stopPropagation } = this.options | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0 || disabled) return // only left button and enabled | ||
const touch = (evt.touches && evt.touches[0]) || (evt.pointerType && evt.pointerType === 'touch' && evt) | ||
const e = touch || evt | ||
// Safari ignores further event handling after mousedown | ||
if (!this.nativeDraggable && Safari && e.target && e.target.tagName.toUpperCase() === 'SELECT') return | ||
if (e.target === this.$el) return true | ||
if (typeof draggable === 'function') { | ||
@@ -173,4 +213,4 @@ if (!draggable(e)) return true | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0) return // only left button and enabled | ||
if (e.target === this.$el) return true | ||
if (evt.preventDefault !== void 0) evt.preventDefault() | ||
if (stopPropagation) evt.stopPropagation() | ||
@@ -219,7 +259,6 @@ try { | ||
this._onUpEvents(touch) | ||
} | ||
}, | ||
_onMove: function(/** Event|TouchEvent */evt) { | ||
if (evt.preventDefault !== void 0) evt.preventDefault() // prevent scrolling | ||
_onMove(evt) { | ||
evt.preventDefault() | ||
const touch = evt.touches && evt.touches[0] | ||
@@ -230,3 +269,6 @@ const e = touch || evt | ||
const { chosenClass } = this.options | ||
const { chosenClass, stopPropagation } = this.options | ||
if (stopPropagation) evt.stopPropagation() | ||
toggleClass(this.dragEl, chosenClass, true) | ||
@@ -238,3 +280,2 @@ this.ghost.move() | ||
document.body.style.cursor = 'grabbing' | ||
window.sortableDndOnMove = true | ||
@@ -247,2 +288,10 @@ | ||
// 判断边界值 | ||
const rc = getRect(this.$el) | ||
if (clientX < rc.left || clientX > rc.right || clientY < rc.top || clientY > rc.bottom) { | ||
this.ghost.setStyle({ cursor: 'not-allowed' }) | ||
return | ||
} | ||
const { index, el, rect, offset } = getElement(this.$el, target) | ||
@@ -253,18 +302,13 @@ const { left, right, top, bottom } = rect | ||
// 判断边界值 | ||
const _rect = getRect(this.$el) | ||
this._checkRange(e, _rect) | ||
// 加上当前滚动距离 | ||
const { scrollTop, scrollLeft } = this.scrollEl | ||
const boundaryL = rc.left + scrollLeft | ||
const boundaryT = rc.top + scrollTop | ||
// 如果目标元素超出当前可视区,不允许拖动 | ||
if (this.scrollEl !== this.$el && (_rect.left < 0 || _rect.top < 0)) { | ||
if (rect.top < (_rect.top + scrollTop) && _rect.top < 0) return | ||
if (rect.left < (_rect.left + scrollLeft) && _rect.left < 0) return | ||
} else { | ||
if (rect.top < _rect.top) return | ||
if (rect.left < _rect.left) return | ||
} | ||
if (this.scrollEl !== this.$el && (rc.left < 0 || rc.top < 0)) { | ||
if ((rc.top < 0 && top < boundaryT) || (rc.left < 0 && left < boundaryL)) return | ||
} else if (top < rc.top || left < rc.left) return | ||
if (clientX > left && clientX < right && clientY > top && clientY < bottom) { | ||
@@ -293,11 +337,11 @@ this.dropEl = el | ||
} | ||
} | ||
_onDrop() { | ||
}, | ||
_onDrop: function(/** Event|TouchEvent */evt) { | ||
this._offMoveEvents() | ||
this._offUpEvents() | ||
document.body.style.cursor = '' | ||
const { dragEnd, chosenClass } = this.options | ||
const { dragEnd, chosenClass, stopPropagation } = this.options | ||
if (stopPropagation) evt.stopPropagation() // 阻止事件冒泡 | ||
toggleClass(this.dragEl, chosenClass, false) | ||
@@ -329,19 +373,11 @@ | ||
this._removeWindowState() | ||
} | ||
}, | ||
_checkRange(e, groupRect) { | ||
const { top, left, right, bottom } = groupRect | ||
if (e.clientX < left || e.clientX > right || e.clientY < top || e.clientY > bottom) { | ||
document.body.style.cursor = 'not-allowed' | ||
return | ||
} | ||
} | ||
// -------------------------------- auto destroy ---------------------------------- | ||
_handleDestroy() { | ||
_handleDestroy: function() { | ||
let observer = null | ||
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver | ||
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver | ||
if (MutationObserver) { | ||
const { ownerDocument } = this.options | ||
if (!ownerDocument) return | ||
observer = new MutationObserver(() => { | ||
@@ -368,6 +404,6 @@ if (!ownerDocument.body.contains(this.$el)) { | ||
} | ||
} | ||
}, | ||
// -------------------------------- reset state ---------------------------------- | ||
_resetState() { | ||
_resetState: function() { | ||
this.dragEl = null | ||
@@ -379,5 +415,4 @@ this.dropEl = null | ||
this._removeWindowState() | ||
} | ||
_removeWindowState() { | ||
}, | ||
_removeWindowState: function() { | ||
window.sortableDndOnDown = null | ||
@@ -388,59 +423,4 @@ window.sortableDndOnMove = null | ||
} | ||
// -------------------------------- listener ---------------------------------- | ||
_bindEventListener() { | ||
this._onStart = this._onStart.bind(this) | ||
this._onMove = this._onMove.bind(this) | ||
this._onDrop = this._onDrop.bind(this) | ||
const { supportPointer } = this.options | ||
if (supportPointer) { | ||
on(this.$el, 'pointerdown', this._onStart) | ||
} else { | ||
on(this.$el, 'mousedown', this._onStart) | ||
on(this.$el, 'touchstart', this._onStart) | ||
} | ||
} | ||
_unbindEventListener() { | ||
off(this.$el, 'pointerdown', this._onStart) | ||
off(this.$el, 'touchstart', this._onStart) | ||
off(this.$el, 'mousedown', this._onStart) | ||
} | ||
_onMoveEvents(touch) { | ||
const { supportPointer, ownerDocument } = this.options | ||
if (supportPointer) { | ||
on(ownerDocument, 'pointermove', this._onMove) | ||
} else if (touch) { | ||
on(ownerDocument, 'touchmove', this._onMove) | ||
} else { | ||
on(ownerDocument, 'mousemove', this._onMove) | ||
} | ||
} | ||
_onUpEvents() { | ||
const { ownerDocument } = this.options | ||
on(ownerDocument, 'pointerup', this._onDrop) | ||
on(ownerDocument, 'touchend', this._onDrop) | ||
on(ownerDocument, 'touchcancel', this._onDrop) | ||
on(ownerDocument, 'mouseup', this._onDrop) | ||
} | ||
_offMoveEvents() { | ||
const { ownerDocument } = this.options | ||
off(ownerDocument, 'pointermove', this._onMove) | ||
off(ownerDocument, 'touchmove', this._onMove) | ||
off(ownerDocument, 'mousemove', this._onMove) | ||
} | ||
_offUpEvents() { | ||
const { ownerDocument } = this.options | ||
off(ownerDocument, 'mouseup', this._onDrop) | ||
off(ownerDocument, 'touchend', this._onDrop) | ||
off(ownerDocument, 'touchcancel', this._onDrop) | ||
off(ownerDocument, 'pointerup', this._onDrop) | ||
} | ||
} | ||
export default Sortable |
@@ -11,2 +11,17 @@ import { IE11OrLess } from './Brower.js' | ||
/** | ||
* detect passive event support | ||
*/ | ||
export function supportPassive() { | ||
// https://github.com/Modernizr/Modernizr/issues/1894 | ||
let supportPassive = false | ||
document.addEventListener('checkIfSupportPassive', null, { | ||
get passive() { | ||
supportPassive = true | ||
return true | ||
} | ||
}) | ||
return supportPassive | ||
} | ||
/** | ||
* add specified event listener | ||
@@ -16,8 +31,9 @@ * @param {HTMLElement} el | ||
* @param {Function} fn | ||
* @param {Boolean} sp | ||
*/ | ||
export function on(el, event, fn) { | ||
export function on(el, event, fn, sp) { | ||
if (window.addEventListener) { | ||
el.addEventListener(event, fn, !IE11OrLess && captureMode) | ||
el.addEventListener(event, fn, (sp || !IE11OrLess) ? captureMode : false) | ||
} else if (window.attachEvent) { | ||
el.addEventListener('on' + event, fn) | ||
el.attachEvent('on' + event, fn) | ||
} | ||
@@ -31,6 +47,7 @@ } | ||
* @param {Function} fn | ||
* @param {Boolean} sp | ||
*/ | ||
export function off(el, event, fn) { | ||
export function off(el, event, fn, sp) { | ||
if (window.removeEventListener) { | ||
el.removeEventListener(event, fn, !IE11OrLess && captureMode) | ||
el.removeEventListener(event, fn, (sp || !IE11OrLess) ? captureMode : false) | ||
} else if (window.detachEvent) { | ||
@@ -302,4 +319,5 @@ el.detachEvent('on' + event, fn) | ||
toggleClass, | ||
supportPassive, | ||
getWindowScrollingElement, | ||
getParentAutoScrollElement, | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
75516
11
1632
78