149 lines
3.7 KiB
Plaintext
149 lines
3.7 KiB
Plaintext
/**
|
|
* @param {Element} eleBar 拖拽触发元素
|
|
* @param {Object} options 可选参数
|
|
* @returns
|
|
*/
|
|
|
|
const startDrag = function (eleBar, options) {
|
|
if (!eleBar) {
|
|
return;
|
|
}
|
|
|
|
// 默认数据
|
|
const defaults = {
|
|
target: eleBar,
|
|
bounding: window,
|
|
edgeLock: true,
|
|
onMove: function () {},
|
|
onEnd: function () {},
|
|
};
|
|
|
|
options = options || {};
|
|
|
|
const params: any = {};
|
|
for (const key in defaults) {
|
|
if (typeof options[key] != 'undefined') {
|
|
params[key] = options[key];
|
|
} else {
|
|
params[key] = defaults[key];
|
|
}
|
|
}
|
|
|
|
// 拖拽元素
|
|
const eleTarget = params.target;
|
|
// 限制范围
|
|
const bounding = params.bounding;
|
|
let objBounding = bounding;
|
|
|
|
// 事件类型处理
|
|
let objEventType = {
|
|
start: 'mousedown',
|
|
move: 'mousemove',
|
|
end: 'mouseup',
|
|
};
|
|
|
|
if ('ontouchstart' in document) {
|
|
objEventType = {
|
|
start: 'touchstart',
|
|
move: 'touchmove',
|
|
end: 'touchend',
|
|
};
|
|
}
|
|
|
|
// 坐标存储数据
|
|
const store: any = {};
|
|
eleBar.addEventListener(objEventType.start, function (event) {
|
|
// IE 拖拽可能拖不动的处理
|
|
if (!window.WeakMap || typeof document.msHidden != 'undefined') {
|
|
event.preventDefault();
|
|
}
|
|
// 兼顾移动端
|
|
if (event.touches && event.touches.length) {
|
|
event = event.touches[0];
|
|
}
|
|
store.y = event.pageY;
|
|
store.x = event.pageX;
|
|
store.isMoving = true;
|
|
store.top = parseFloat(getComputedStyle(eleTarget).top) || 0;
|
|
store.left = parseFloat(getComputedStyle(eleTarget).left) || 0;
|
|
|
|
if (params.edgeLock === true && bounding) {
|
|
if (bounding === window) {
|
|
objBounding = {
|
|
left: 0,
|
|
top: 0,
|
|
bottom: innerHeight,
|
|
right: Math.min(innerWidth, document.documentElement.clientWidth),
|
|
};
|
|
} else if (bounding.tagName) {
|
|
objBounding = bounding.getBoundingClientRect();
|
|
}
|
|
|
|
// 拖拽元素的 bounding 位置
|
|
const objBoundingTarget = eleTarget.getBoundingClientRect();
|
|
|
|
// 可移动范围
|
|
store.range = {
|
|
y: [objBounding.top - objBoundingTarget.top, objBounding.bottom - objBoundingTarget.bottom],
|
|
x: [objBounding.left - objBoundingTarget.left, objBounding.right - objBoundingTarget.right],
|
|
};
|
|
}
|
|
});
|
|
document.addEventListener(
|
|
objEventType.move,
|
|
function (event: any) {
|
|
if (store.isMoving) {
|
|
event.preventDefault();
|
|
// 兼顾移动端
|
|
if (event.touches && event.touches.length) {
|
|
event = event.touches[0];
|
|
}
|
|
|
|
let distanceY = event.pageY - store.y;
|
|
let distanceX = event.pageX - store.x;
|
|
|
|
// 边界的判断与chuli
|
|
if (params.edgeLock === true && bounding) {
|
|
const minX = Math.min.apply(null, store.range.x);
|
|
const maxX = Math.max.apply(null, store.range.x);
|
|
const minY = Math.min.apply(null, store.range.y);
|
|
const maxY = Math.max.apply(null, store.range.y);
|
|
|
|
if (distanceX < minX) {
|
|
distanceX = minX;
|
|
} else if (distanceX > maxX) {
|
|
distanceX = maxX;
|
|
}
|
|
|
|
if (distanceY < minY) {
|
|
distanceY = minY;
|
|
} else if (distanceY > maxY) {
|
|
distanceY = maxY;
|
|
}
|
|
}
|
|
|
|
const top = store.top + distanceY;
|
|
const left = store.left + distanceX;
|
|
|
|
eleTarget.style.top = top + 'px';
|
|
eleTarget.style.left = left + 'px';
|
|
|
|
// 回调
|
|
params.onMove(left, top);
|
|
}
|
|
},
|
|
{
|
|
passive: false,
|
|
},
|
|
);
|
|
document.addEventListener(objEventType.end, function () {
|
|
if (store.isMoving) {
|
|
store.isMoving = false;
|
|
|
|
params.onEnd();
|
|
}
|
|
});
|
|
};
|
|
|
|
export default startDrag;
|