card-drag-sort
Version:
Vue3卡片拖拽排序组件
207 lines (206 loc) • 7.74 kB
JavaScript
import './index.css';
import { defineComponent, useCssVars, computed, ref, openBlock, createElementBlock, Fragment, renderList, normalizeStyle, createElementVNode, renderSlot, toDisplayString, pushScopeId, popScopeId } from "vue";
const _withScopeId = (n) => (pushScopeId("data-v-5a9c119d"), n = n(), popScopeId(), n);
const _hoisted_1 = ["id"];
const _hoisted_2 = ["onMousedown"];
const _hoisted_3 = { class: "card-title" };
const _hoisted_4 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElementVNode("div", { class: "empty-text" }, "暂无内容", -1));
const _sfc_main = /* @__PURE__ */ defineComponent({
...{ name: "CardDragSort" },
__name: "index",
props: {
data: { type: Array, required: true },
columns: { type: Number, default: 3 },
width: { type: Number, default: 500 },
height: { type: Number, default: 300 },
columnSpace: { type: Number, default: 20 },
rowSpace: { type: Number, default: 20 },
duration: { type: Number, default: 200 }
},
emits: ["dragStart", "dragStop"],
setup(__props, { emit: __emit }) {
useCssVars((_ctx) => ({
"57911cb1": containerHeight.value,
"f41f9bea": duration.value
}));
const emit = __emit;
const props = __props;
const dataList = computed(() => {
return props.data.map((item, index) => {
return { index, ...item };
});
});
const containerHeight = computed(() => {
const num = dataList.value.length;
return Math.ceil(num / props.columns - 1) * (props.height + props.rowSpace) + props.height + "px";
});
const duration = computed(() => {
return props.duration + "ms";
});
function cardPositionTop(index) {
return Math.floor(index / props.columns) * (props.height + props.rowSpace) + "px";
}
function cardPositionLeft(index) {
return index % props.columns * (props.width + props.columnSpace) + "px";
}
let dragDom;
let dragDomData;
let domStartY;
let domStartX;
let mouseStartY;
let mouseStartX;
let moveY = 0;
let moveX = 0;
let scrollStart;
let scrollLength = 0;
let throttleFn;
let transitionEnd = true;
function dragStart(e, id) {
if (!transitionEnd)
return;
emit("dragStart", id);
const card = document.getElementById(id);
if (!card)
return;
dragDom = card;
dragDomData = dataList.value.find((item) => {
return item.id === id;
});
domStartY = parseInt(dragDom.style.top);
domStartX = parseInt(dragDom.style.left);
dragDom.style.zIndex = "100";
dragDom.style.transition = "none";
mouseStartY = e.clientY;
mouseStartX = e.clientX;
scrollStart = document.documentElement.scrollTop;
document.addEventListener("mousemove", dragMove);
document.addEventListener("mouseup", dragStop);
document.addEventListener("scroll", scroll);
dragDom.addEventListener("transitionend", dragTransitionend);
}
function dragMove(e) {
moveY = domStartY + (e.clientY - mouseStartY);
moveX = domStartX + (e.clientX - mouseStartX);
dragDom.style.top = moveY + scrollLength + "px";
dragDom.style.left = moveX + "px";
throttleFn = setTimeout(() => {
findCoveredDom(parseInt(dragDom.style.top), parseInt(dragDom.style.left));
clearTimeout(throttleFn);
}, props.duration);
}
const cardDrag = ref();
function findCoveredDom(domY, domX) {
const domList = Array.from(cardDrag.value.children);
for (const item of domList) {
const relativeY = domY - parseInt(item.style.top);
const relativeX = domX - parseInt(item.style.left);
if (Math.abs(relativeY) < props.height / 2 && Math.abs(relativeX) < props.width / 2 && dragDomData && item.id !== dragDomData.id) {
const coveredData = dataList.value.find((dataItem) => {
return item.id === dataItem.id;
});
if (!coveredData || coveredData.id === dragDomData.id)
return;
const newIndex = coveredData.index;
const bigSmall = dragDomData.index > coveredData.index;
let transitionDataList;
if (bigSmall) {
transitionDataList = dataList.value.filter((item2) => {
if (item2.index >= coveredData.index && item2.index < dragDomData.index) {
item2.index += 1;
return item2;
}
});
} else {
transitionDataList = dataList.value.filter((item2) => {
if (item2.index <= coveredData.index && item2.index > dragDomData.index) {
item2.index -= 1;
return item2;
}
});
}
dragDomData.index = newIndex;
for (const tranItem of transitionDataList) {
const el = document.getElementById(tranItem.id);
if (el) {
el.style.top = cardPositionTop(tranItem.index);
el.style.left = cardPositionLeft(tranItem.index);
}
}
}
}
}
function dragStop() {
transitionEnd = false;
dataList.value.sort((a, b) => a.index - b.index);
emit("dragStop", dataList.value);
document.removeEventListener("mousemove", dragMove);
document.removeEventListener("mouseup", dragStop);
document.removeEventListener("scroll", scroll);
dragDom.style.transition = `all ${duration.value}`;
dragDom.style.top = domStartY + "px";
dragDom.style.left = domStartX + "px";
dragDom.style.zIndex = "0";
dragDom.style.top = cardPositionTop(dragDomData.index);
dragDom.style.left = cardPositionLeft(dragDomData.index);
}
function scroll() {
scrollLength = document.documentElement.scrollTop - scrollStart;
dragDom.style.top = moveY + scrollLength + "px";
}
function dragTransitionend() {
transitionEnd = true;
this.removeEventListener("transitionend", dragTransitionend);
}
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
class: "card-drag-sort",
ref_key: "cardDrag",
ref: cardDrag
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(dataList.value, (item) => {
return openBlock(), createElementBlock("div", {
class: "card-wrap",
key: item.id,
id: item.id,
style: normalizeStyle({
width: `${__props.width}px`,
height: `${__props.height}px`,
top: cardPositionTop(item.index),
left: cardPositionLeft(item.index)
})
}, [
createElementVNode("div", {
class: "card-header",
onMousedown: ($event) => dragStart($event, item.id)
}, [
renderSlot(_ctx.$slots, "header", { card: item }, () => [
createElementVNode("div", _hoisted_3, toDisplayString(item.title || "无标题"), 1)
], true)
], 40, _hoisted_2),
renderSlot(_ctx.$slots, "content", { card: item }, () => [
_hoisted_4
], true)
], 12, _hoisted_1);
}), 128))
], 512);
};
}
});
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const CardDragSort = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-5a9c119d"]]);
const components = [CardDragSort];
const install = (app) => {
components.forEach((component) => {
app.component(component.__name, component);
});
};
export {
CardDragSort,
install as default
};