228 lines
6.6 KiB
JavaScript
228 lines
6.6 KiB
JavaScript
|
|
/* eslint-disable no-plusplus */
|
||
|
|
let classPrefix = '';
|
||
|
|
let startIndex = 0;
|
||
|
|
let endIndex = 0;
|
||
|
|
let dragCollisionList = [];
|
||
|
|
|
||
|
|
const isOutRange = function (x1, y1, x2, y2, x3, y3) {
|
||
|
|
return x1 < 0 || x1 >= y1 || x2 < 0 || x2 >= y2 || x3 < 0 || x3 >= y3;
|
||
|
|
};
|
||
|
|
|
||
|
|
const sortCore = function (sKey, eKey, st) {
|
||
|
|
const _ = st.dragBaseData;
|
||
|
|
|
||
|
|
const excludeFix = function (cKey, type) {
|
||
|
|
if (st.list[cKey].fixed) {
|
||
|
|
// fixed 元素位置不会变化, 这里直接用 cKey(sortKey) 获取, 更加快捷
|
||
|
|
type ? --cKey : ++cKey;
|
||
|
|
return excludeFix(cKey, type);
|
||
|
|
}
|
||
|
|
return cKey;
|
||
|
|
};
|
||
|
|
|
||
|
|
// 先获取到 endKey 对应的 realKey, 防止下面排序过程中该 realKey 被修改
|
||
|
|
let endRealKey = -1;
|
||
|
|
st.list.forEach((item) => {
|
||
|
|
if (item.sortKey === eKey) endRealKey = item.realKey;
|
||
|
|
});
|
||
|
|
|
||
|
|
return st.list.map((item) => {
|
||
|
|
if (item.fixed) return item;
|
||
|
|
let cKey = item.sortKey;
|
||
|
|
let rKey = item.realKey;
|
||
|
|
|
||
|
|
if (sKey < eKey) {
|
||
|
|
// 正序拖动
|
||
|
|
if (cKey > sKey && cKey <= eKey) {
|
||
|
|
--rKey;
|
||
|
|
cKey = excludeFix(--cKey, true);
|
||
|
|
} else if (cKey === sKey) {
|
||
|
|
rKey = endRealKey;
|
||
|
|
cKey = eKey;
|
||
|
|
}
|
||
|
|
} else if (sKey > eKey) {
|
||
|
|
// 倒序拖动
|
||
|
|
if (cKey >= eKey && cKey < sKey) {
|
||
|
|
++rKey;
|
||
|
|
cKey = excludeFix(++cKey, false);
|
||
|
|
} else if (cKey === sKey) {
|
||
|
|
rKey = endRealKey;
|
||
|
|
cKey = eKey;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (item.sortKey !== cKey) {
|
||
|
|
item.tranX = `${(cKey % _.columns) * 100}%`;
|
||
|
|
item.tranY = `${Math.floor(cKey / _.columns) * 100}%`;
|
||
|
|
item.sortKey = cKey;
|
||
|
|
item.realKey = rKey;
|
||
|
|
}
|
||
|
|
return item;
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
function triggerCustomEvent(list, type, ins) {
|
||
|
|
const _list = [];
|
||
|
|
const listData = [];
|
||
|
|
|
||
|
|
list.forEach((item) => {
|
||
|
|
_list[item.sortKey] = item;
|
||
|
|
});
|
||
|
|
|
||
|
|
_list.forEach((item) => {
|
||
|
|
if (!item.extraNode) {
|
||
|
|
listData.push(item.data);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
ins.$emit(type, { listData });
|
||
|
|
}
|
||
|
|
|
||
|
|
export function longPress(event, index) {
|
||
|
|
const st = this.getState();
|
||
|
|
const _ = st.dragBaseData;
|
||
|
|
|
||
|
|
const sTouch = event.changedTouches[0];
|
||
|
|
if (!sTouch) return;
|
||
|
|
|
||
|
|
st.cur = index;
|
||
|
|
|
||
|
|
// compile error
|
||
|
|
// longPressIndex = st.cur;
|
||
|
|
|
||
|
|
// 初始项是固定项则返回
|
||
|
|
const item = st.list[st.cur];
|
||
|
|
if (item && item.fixed) return;
|
||
|
|
|
||
|
|
// 如果已经在 drag 中则返回, 防止多指触发 drag 动作, touchstart 事件中有效果
|
||
|
|
if (st.dragging) return;
|
||
|
|
st.dragging = true;
|
||
|
|
this.callMethod('dragStatusChange', { dragging: true });
|
||
|
|
|
||
|
|
// 计算X,Y轴初始位移, 使 item 中心移动到点击处, 单列时候X轴初始不做位移
|
||
|
|
st.tranX = _.columns === 1 ? 0 : sTouch.pageX - (_.itemWidth / 2 + _.wrapLeft);
|
||
|
|
st.tranY = sTouch.pageY - (_.itemHeight / 2 + _.wrapTop);
|
||
|
|
st.sId = sTouch.identifier;
|
||
|
|
this.setDragItemStyle(index, `transform: translate3d(${st.tranX}px, ${st.tranY}px, 0)`);
|
||
|
|
|
||
|
|
st.list.forEach((item, index) => {
|
||
|
|
this.setDragItemClass(index, 'remove', [`${classPrefix}__drag--tran`, `${classPrefix}__drag--cur`]);
|
||
|
|
this.setDragItemClass(index, 'add', index === st.cur ? `${classPrefix}__drag--cur` : `${classPrefix}__drag--tran`);
|
||
|
|
});
|
||
|
|
this.callMethod('dragVibrate', { vibrateType: 'longPress' });
|
||
|
|
}
|
||
|
|
|
||
|
|
export function touchMove(event, index) {
|
||
|
|
// const ins = event.instance;
|
||
|
|
const st = this.getState();
|
||
|
|
const _ = st.dragBaseData;
|
||
|
|
|
||
|
|
const mTouch = event.changedTouches[0];
|
||
|
|
if (!mTouch) return;
|
||
|
|
|
||
|
|
if (!st.dragging) return;
|
||
|
|
|
||
|
|
// 如果不是同一个触发点则返回
|
||
|
|
if (st.sId !== mTouch.identifier) return;
|
||
|
|
|
||
|
|
// 计算X,Y轴位移, 单列时候X轴初始不做位移
|
||
|
|
const tranX = _.columns === 1 ? 0 : mTouch.pageX - (_.itemWidth / 2 + _.wrapLeft);
|
||
|
|
const tranY = mTouch.pageY - (_.itemHeight / 2 + _.wrapTop);
|
||
|
|
|
||
|
|
// 到顶到底自动滑动
|
||
|
|
if (mTouch.clientY > _.windowHeight - _.itemHeight - _.realBottomSize) {
|
||
|
|
// 当前触摸点pageY + item高度 - (屏幕高度 - 底部固定区域高度)
|
||
|
|
this.callMethod('pageScroll', {
|
||
|
|
scrollTop: mTouch.pageY + _.itemHeight - (_.windowHeight - _.realBottomSize),
|
||
|
|
});
|
||
|
|
} else if (mTouch.clientY < _.itemHeight + _.realTopSize) {
|
||
|
|
// 当前触摸点pageY - item高度 - 顶部固定区域高度
|
||
|
|
this.callMethod('pageScroll', {
|
||
|
|
scrollTop: mTouch.pageY - _.itemHeight - _.realTopSize,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置当前激活元素偏移量
|
||
|
|
this.setDragItemStyle(index, `transform: translate3d(${tranX}px, ${tranY}px, 0)`);
|
||
|
|
|
||
|
|
const startKey = st.list[st.cur].sortKey;
|
||
|
|
const curX = Math.round(tranX / _.itemWidth);
|
||
|
|
const curY = Math.round(tranY / _.itemHeight);
|
||
|
|
const endKey = curX + _.columns * curY;
|
||
|
|
|
||
|
|
// 目标项是固定项则返回
|
||
|
|
const item = st.list[endKey];
|
||
|
|
if (item && item.fixed) return;
|
||
|
|
|
||
|
|
// X轴或Y轴超出范围则返回
|
||
|
|
if (isOutRange(curX, _.columns, curY, _.rows, endKey, st.list.length)) return;
|
||
|
|
|
||
|
|
// 防止拖拽过程中发生乱序问题
|
||
|
|
if (startKey === endKey || startKey === st.preStartKey) return;
|
||
|
|
st.preStartKey = startKey;
|
||
|
|
|
||
|
|
dragCollisionList = sortCore(startKey, endKey, st);
|
||
|
|
startIndex = startKey;
|
||
|
|
endIndex = endKey;
|
||
|
|
st.list.forEach((_, index) => {
|
||
|
|
const item = dragCollisionList[index];
|
||
|
|
if (index !== st.cur) {
|
||
|
|
this.setDragItemStyle(index, `transform: translate3d(${item.tranX},${item.tranY}, 0)`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
this.callMethod('dragVibrate', { vibrateType: 'touchMove' });
|
||
|
|
this.callMethod('dragCollision', {
|
||
|
|
dragCollisionList,
|
||
|
|
startIndex,
|
||
|
|
endIndex,
|
||
|
|
});
|
||
|
|
triggerCustomEvent(dragCollisionList, 'change', this);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function touchEnd(event, index) {
|
||
|
|
const st = this.getState();
|
||
|
|
|
||
|
|
if (!st.dragging) return;
|
||
|
|
triggerCustomEvent(st.list, 'sortend', this);
|
||
|
|
|
||
|
|
this.setDragItemClass(index, 'remove', `${classPrefix}__drag--cur`);
|
||
|
|
this.setDragItemClass(index, 'add', `${classPrefix}__drag--tran`);
|
||
|
|
|
||
|
|
this.setDragItemStyle(index, `transform: translate3d(${st.list[st.cur].tranX},${st.list[st.cur].tranY}, 0)`);
|
||
|
|
|
||
|
|
st.preStartKey = -1;
|
||
|
|
st.dragging = false;
|
||
|
|
this.callMethod('dragStatusChange', { dragging: false });
|
||
|
|
this.callMethod('dragEnd', {
|
||
|
|
dragCollisionList,
|
||
|
|
startIndex,
|
||
|
|
endIndex,
|
||
|
|
});
|
||
|
|
st.cur = -1;
|
||
|
|
st.tranX = 0;
|
||
|
|
st.tranY = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function baseDataObserver(newVal) {
|
||
|
|
if (newVal === undefined) return;
|
||
|
|
|
||
|
|
const st = this.getState();
|
||
|
|
st.dragBaseData = newVal;
|
||
|
|
classPrefix = newVal.classPrefix;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function listObserver(newVal) {
|
||
|
|
if (newVal === undefined) return;
|
||
|
|
|
||
|
|
const st = this.getState();
|
||
|
|
|
||
|
|
st.list = newVal || [];
|
||
|
|
st.list.forEach((item, index) => {
|
||
|
|
this.setDragItemClass(index, 'remove', `${classPrefix}__drag--tran`);
|
||
|
|
this.setDragItemStyle(index, `transform: translate3d(${item.tranX},${item.tranY}, 0)`);
|
||
|
|
if (item.fixed) this.setDragItemClass(index, 'add', `${classPrefix}__drag--fixed`);
|
||
|
|
});
|
||
|
|
dragCollisionList = [];
|
||
|
|
}
|