a-draggable-component
Version:
一个可以托拽的vue3+typescript组件,主要应用场景:两个子空间的拖拽状态的相互转换
619 lines (618 loc) • 21.7 kB
JavaScript
import { defineComponent, computed, openBlock, createElementBlock, normalizeStyle, createElementVNode, ref, reactive, Fragment, renderList, renderSlot, mergeDefaults, unref, createBlock, createCommentVNode, onMounted, onUnmounted } from "vue";
if (typeof window !== "undefined") {
let loadSvg = function() {
var body = document.body;
var svgDom = document.getElementById("__svg__icons__dom__");
if (!svgDom) {
svgDom = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgDom.style.position = "absolute";
svgDom.style.width = "0";
svgDom.style.height = "0";
svgDom.id = "__svg__icons__dom__";
svgDom.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svgDom.setAttribute("xmlns:link", "http://www.w3.org/1999/xlink");
}
svgDom.innerHTML = '<symbol viewBox="64 64 896 896" fill="currentColor" aria-hidden="true" id="icon-arrowRight"><path d="M765.7 486.8 314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z" /></symbol>';
body.insertBefore(svgDom, body.lastChild);
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", loadSvg);
} else {
loadSvg();
}
}
const _hoisted_1$1 = ["fill"];
const _hoisted_2$1 = ["xlink:href", "fill"];
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
__name: "index",
props: {
name: {},
prefix: { default: "icon" },
iconStyle: { default: () => ({ width: "30px", height: "30px" }) },
color: { default: "#333" }
},
setup(__props) {
const props = __props;
const symbolId = computed(() => `#${props.prefix}-${props.name}`);
return (_ctx, _cache) => {
return openBlock(), createElementBlock("svg", {
style: normalizeStyle({ ..._ctx.iconStyle, color: _ctx.color }),
"aria-hidden": "true",
fill: _ctx.color
}, [
createElementVNode("use", {
"xlink:href": symbolId.value,
fill: _ctx.color
}, null, 8, _hoisted_2$1)
], 12, _hoisted_1$1);
};
}
});
const CallbackMap = /* @__PURE__ */ new WeakMap();
const mouseAddListener = (dom, callbackObj) => {
if (CallbackMap.has(dom)) {
const list = CallbackMap.get(dom);
list.push(callbackObj);
CallbackMap.set(dom, list);
} else {
CallbackMap.set(dom, [callbackObj]);
}
if (callbackObj.mousemoveFn) {
dom.addEventListener("mousemove", (e) => {
callbackObj.mousemoveFn(e, dom);
});
}
if (callbackObj.mouseupFn) {
dom.addEventListener("mouseup", (e) => {
callbackObj.mouseupFn(e, dom);
});
}
if (callbackObj.mousedownFn) {
dom.addEventListener("mousedown", (e) => {
callbackObj.mousedownFn(e, dom);
});
}
};
const mouseRemoveListener = (dom) => {
const callbackObjList = CallbackMap.get(dom);
if (callbackObjList && callbackObjList.length) {
callbackObjList.forEach((callbackObj) => {
if (callbackObj.mousemoveFn) {
dom.removeEventListener("mousemove", callbackObj.mousemoveFn);
}
if (callbackObj.mouseupFn) {
dom.removeEventListener("mouseup", callbackObj.mouseupFn);
}
if (callbackObj.mousedownFn) {
dom.removeEventListener("mousedown", callbackObj.mousedownFn);
}
});
CallbackMap.delete(dom);
}
};
const isUp = (newDisY, disY) => {
return newDisY - disY < 0;
};
const isDown = (newDisY, disY) => {
return newDisY - disY > 0;
};
const isLeft = (newDisX, disX) => {
return newDisX - disX < 0;
};
const isRight = (newDisX, disX) => {
return newDisX - disX > 0;
};
const moveDefalutElement = (e, actions, options) => {
const { width, height, top, left, topStyle = {}, leftStyle = {}, bottomStyle = {}, rightStyle = {} } = options || {};
const moveDisX = e.clientX - actions.initX;
const moveDisY = e.clientY - actions.initY;
const w = width.value || 0;
const h = height.value || 0;
const t = top.value || 0;
const l = left.value || 0;
if (actions.type === "default") {
top.value = t + moveDisY;
left.value = l + moveDisX;
actions.initX = e.clientX;
actions.initY = e.clientY;
} else {
if (isUp(e.clientY, actions.initY) && (actions.type === "top" || actions.type === "bottom")) {
console.log("direction isUp");
if (actions.type === "top") {
height.value = h - moveDisY;
top.value = t + moveDisY;
}
if (actions.type === "bottom") {
height.value = h + moveDisY;
}
actions.initY = e.clientY;
}
if (isDown(e.clientY, actions.initY) && (actions.type === "top" || actions.type === "bottom")) {
console.log("direction isDown");
if (actions.type === "top") {
height.value = h - moveDisY;
top.value = t + moveDisY;
}
if (actions.type === "bottom") {
height.value = h + moveDisY;
}
actions.initY = e.clientY;
}
if (isLeft(e.clientX, actions.initX) && (actions.type === "left" || actions.type === "right")) {
console.log("direction isLeft");
if (actions.type === "left") {
width.value = w - moveDisX;
left.value = l + moveDisX;
}
if (actions.type === "right") {
width.value = w + moveDisX;
}
actions.initX = e.clientX;
}
if (isRight(e.clientX, actions.initX) && (actions.type === "left" || actions.type === "right")) {
console.log("direction isRight");
if (actions.type === "left") {
width.value = w - moveDisX;
left.value = l + moveDisX;
}
if (actions.type === "right") {
width.value = w + moveDisX;
}
actions.initX = e.clientX;
}
}
};
const initActions = (actions) => {
actions.initX = 0;
actions.initY = 0;
actions.state = "";
actions.type = "";
};
const moveDraggableElement = (type, list, topList, draggableIndex, draggableType) => {
if (type === "top" && draggableType.value !== type) {
const ele = list[draggableIndex.value];
if (draggableIndex.value !== -1) {
ele.position = type;
list.splice(draggableIndex.value, 1);
topList.push(ele);
draggableIndex.value = -1;
}
}
if (type === "bottom" && draggableType.value !== type) {
const ele = topList[draggableIndex.value];
if (draggableIndex.value !== -1) {
ele.position = type;
topList.splice(draggableIndex.value, 1);
list.push(ele);
draggableIndex.value = -1;
}
}
};
function mitt(n) {
return { all: n = n || /* @__PURE__ */ new Map(), on: function(t, e) {
var i = n.get(t);
i ? i.push(e) : n.set(t, [e]);
}, off: function(t, e) {
var i = n.get(t);
i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []));
}, emit: function(t, e) {
var i = n.get(t);
i && i.slice().map(function(n2) {
n2(e);
}), (i = n.get("*")) && i.slice().map(function(n2) {
n2(t, e);
});
} };
}
let emitter = null;
const EventBus = () => {
if (emitter) {
return emitter;
}
return emitter = mitt();
};
const _hoisted_1 = ["onDragstart", "draggable"];
const _hoisted_2 = ["onDragstart", "draggable"];
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
__name: "index",
props: {
childNum: { default: 4 },
squareBottomIndex: { default: 10 },
squareContentIndex: { default: 10 },
squareBottomHeight: { default: 200 },
mainContainerStyle: { default: { height: 600, width: 1e3, zIndex: 10 } },
childList: {}
},
emits: ["dragType"],
setup(__props, { emit: __emit }) {
const emmiter = EventBus();
const props = __props;
let defalutSquareBottomHeight = ref(props.squareBottomHeight);
const comSquareBottomHeight = computed(() => {
const height = defalutSquareBottomHeight.value;
if (typeof height === "string") {
if (height.includes("%") || height.includes("vh")) {
const num = height.replace("vh", "").replace("%", "");
return windowHeight * (Number(num) / 100);
} else {
return 200;
}
} else {
return Number(props.squareBottomHeight);
}
});
const list = reactive([]);
const topList = reactive([]);
const topSquareRef = ref(null);
const bottomSquareRef = ref(null);
const mainHeight = computed(() => {
return props.mainContainerStyle.height - comSquareBottomHeight.value;
});
function init() {
for (let i = 0; i < props.childNum; i++) {
list[i] = {
key: "square-bottom" + (i + 1),
name: "childSlot" + (i + 1)
};
}
if (props == null ? void 0 : props.childList) {
list.forEach((lObj, i) => {
list[i].position = "bottom";
const others = props.childList[i] || {};
list[i] = {
...lObj,
...others
};
});
}
}
init();
const bottomDraggable = ref(true);
const topDraggable = ref(true);
const draggableIndex = ref(-1);
const draggableType = ref("");
const draggableKey = ref("-1");
emmiter.on("clickContainer", (key) => {
console.log("key ", key);
draggableKey.value = key;
});
emmiter.on("mouseEnter", (state) => {
topDraggable.value = !state;
});
const emits = __emit;
const sqaureDragStart = (type, _, i) => {
draggableIndex.value = i;
draggableType.value = type;
};
const sqaureDragEnter = (type) => {
moveDraggableElement(type, list, topList, draggableIndex, draggableType);
emits("dragType", { type, i: draggableIndex.value, key: draggableKey.value });
};
return (_ctx, _cache) => {
var _a, _b, _c, _d;
return openBlock(), createElementBlock("div", {
class: "main-container",
style: normalizeStyle({
height: ((_a = _ctx.mainContainerStyle) == null ? void 0 : _a.height) + "px",
width: ((_b = _ctx.mainContainerStyle) == null ? void 0 : _b.width) ? ((_c = _ctx.mainContainerStyle) == null ? void 0 : _c.width) + "px" : "100%",
zIndex: (_d = _ctx.mainContainerStyle) == null ? void 0 : _d.zIndex
})
}, [
createElementVNode("div", {
class: "square-content",
ref_key: "topSquareRef",
ref: topSquareRef,
onDragenter: _cache[0] || (_cache[0] = (e) => {
sqaureDragEnter("top");
}),
style: normalizeStyle({ height: mainHeight.value + "px", zIndex: _ctx.squareContentIndex })
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(topList, (child, i) => {
return openBlock(), createElementBlock("div", {
key: child.key,
onDragstart: (e) => {
sqaureDragStart("top", e, i);
},
draggable: topDraggable.value
}, [
renderSlot(_ctx.$slots, child.name, { data: child }, void 0, true)
], 40, _hoisted_1);
}), 128))
], 36),
createElementVNode("div", {
class: "square-bottom",
style: normalizeStyle({ height: comSquareBottomHeight.value + "px", zIndex: _ctx.squareBottomIndex }),
ref_key: "bottomSquareRef",
ref: bottomSquareRef,
onDragenter: _cache[1] || (_cache[1] = (e) => {
sqaureDragEnter("bottom");
})
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(list, (child, i) => {
return openBlock(), createElementBlock("div", {
key: child.key,
onDragstart: (e) => {
sqaureDragStart("bottom", e, i);
},
draggable: bottomDraggable.value
}, [
renderSlot(_ctx.$slots, child.name, { data: child }, void 0, true)
], 40, _hoisted_2);
}), 128))
], 36)
], 4);
};
}
});
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const ADraggableMain = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-b6f4cdc8"]]);
const showOptions = {
showLeft: true,
showRight: true,
showTop: true,
showBottom: true,
showTopLeft: false,
showTopRight: false,
showBottomLeft: false,
showBottomRight: false
};
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "index",
props: /* @__PURE__ */ mergeDefaults({
showLeft: { type: Boolean },
showRight: { type: Boolean },
showTop: { type: Boolean },
showBottom: { type: Boolean },
showTopLeft: { type: Boolean },
showTopRight: { type: Boolean },
showBottomLeft: { type: Boolean },
showBottomRight: { type: Boolean },
componentStyle: {},
topStyle: {},
leftStyle: {},
bottomStyle: {},
rightStyle: {},
height: {},
width: {},
top: {},
left: {},
labelKey: {},
canDragSquare: { type: Boolean },
containerIndex: {}
}, {
labelKey: "-1",
containerIndex: 11,
canDragSquare: false,
...showOptions
}),
setup(__props) {
const emmiter = EventBus();
const props = __props;
const publicStyleAttrs = { zIndex: props.containerIndex + 100 };
const topStyleAttrs = props.topStyle ? { ...props.topStyle, ...publicStyleAttrs } : { ...publicStyleAttrs };
const leftStyleAttrs = props.leftStyle ? { ...props.leftStyle, ...publicStyleAttrs } : { ...publicStyleAttrs };
const bottomStyleAttrs = props.bottomStyle ? { ...props.bottomStyle, ...publicStyleAttrs } : { ...publicStyleAttrs };
const rightStyleAttrs = props.rightStyle ? { ...props.rightStyle, ...publicStyleAttrs } : { ...publicStyleAttrs };
const componentStyle = props.componentStyle || {};
const cWidth = Number((componentStyle.width || "0").replace("px", ""));
const cHeight = Number((componentStyle.height || "0").replace("px", ""));
const cTop = Number((componentStyle.top || "0").replace("px", ""));
const cLeft = Number((componentStyle.left || "0").replace("px", ""));
const width = ref(props.width || cWidth || 200);
const height = ref(props.height || cHeight || 200);
const top = ref(props.top || cTop || 0);
const left = ref(props.left || cLeft || 0);
const leftRef = ref(null);
const rightRef = ref(null);
const topRef = ref(null);
const bottomRef = ref(null);
const defaultRef = ref(null);
const actions = reactive({
type: "",
// 触发的边框状态 left right top down
initX: 0,
initY: 0,
state: "",
mousedownFn: (e) => {
actions.state = "down";
actions.initX = e.clientX;
actions.initY = e.clientY;
},
mouseupFn: (e) => {
actions.state = "up";
moveDefalutElement(e, actions, { width, height, top, left });
initActions(actions);
}
});
const defaultActions = {
mousedownFn: (e) => {
if (actions.state === "") {
actions.type = "default";
actions.state = "default-down";
actions.initX = e.clientX;
actions.initY = e.clientY;
}
},
mouseupFn: (e) => {
if (actions.state === "default-down") {
actions.type = "default";
actions.state = "default-up";
moveDefalutElement(e, actions, { width, height, top, left });
}
initActions(actions);
}
};
const documentActions = {
mousemoveFn: (e) => {
if (actions.state === "down") {
moveDefalutElement(e, actions, {
width,
height,
top,
left,
topStyle: props.topStyle,
leftStyle: props.leftStyle,
bottomStyle: props.bottomStyle,
rightStyle: props.rightStyle
});
}
if (actions.state === "default-down") {
moveDefalutElement(e, actions, {
width,
height,
top,
left,
topStyle: props.topStyle,
leftStyle: props.leftStyle,
bottomStyle: props.bottomStyle,
rightStyle: props.rightStyle
});
}
}
};
const mouseEventFn = (type, state) => {
emmiter.emit("mouseEnter", state);
actions.type = type;
if (state === false) {
actions.state = "";
}
};
const addDomListener = () => {
mouseAddListener(document, documentActions);
(props == null ? void 0 : props.showLeft) && mouseAddListener(leftRef.value, actions);
(props == null ? void 0 : props.showRight) && mouseAddListener(rightRef.value, actions);
(props == null ? void 0 : props.showTop) && mouseAddListener(topRef.value, actions);
(props == null ? void 0 : props.showBottom) && mouseAddListener(bottomRef.value, actions);
(props == null ? void 0 : props.canDragSquare) && mouseAddListener(defaultRef.value, defaultActions);
};
const removeDomListener = () => {
mouseRemoveListener(document);
mouseRemoveListener(leftRef.value);
mouseRemoveListener(rightRef.value);
mouseRemoveListener(topRef.value);
mouseRemoveListener(bottomRef.value);
if (props.canDragSquare) {
mouseRemoveListener(defaultRef.value);
}
};
const init = () => {
onMounted(() => {
addDomListener();
});
onUnmounted(() => {
removeDomListener();
});
};
init();
const clickContainer = () => {
emmiter.emit("clickContainer", props.labelKey);
};
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
class: "margin-label-container",
style: normalizeStyle({
zIndex: _ctx.containerIndex,
...props.componentStyle || {},
...width.value && { width: width.value + "px" },
...height.value && { height: height.value + "px" },
...top.value && { top: top.value + "px" },
...left.value && { left: left.value + "px" }
}),
ref_key: "defaultRef",
ref: defaultRef,
onMouseenter: clickContainer
}, [
_ctx.showTop ? (openBlock(), createElementBlock("div", {
key: 0,
class: "top separator separator-horizontal",
style: normalizeStyle(unref(topStyleAttrs)),
onMouseenter: _cache[0] || (_cache[0] = ($event) => mouseEventFn("top", true)),
onMouseout: _cache[1] || (_cache[1] = ($event) => mouseEventFn("top", false)),
ref_key: "topRef",
ref: topRef
}, [
!_ctx.topStyle ? (openBlock(), createBlock(unref(_sfc_main$2), {
key: 0,
name: "arrowRight",
color: "#666",
iconStyle: { width: "1em", height: "1em" }
})) : createCommentVNode("", true)
], 36)) : createCommentVNode("", true),
_ctx.showLeft ? (openBlock(), createElementBlock("div", {
key: 1,
class: "left separator separator-vertical",
style: normalizeStyle(unref(leftStyleAttrs)),
onMouseenter: _cache[2] || (_cache[2] = ($event) => mouseEventFn("left", true)),
onMouseout: _cache[3] || (_cache[3] = ($event) => mouseEventFn("left", false)),
ref_key: "leftRef",
ref: leftRef
}, [
!_ctx.leftStyle ? (openBlock(), createBlock(unref(_sfc_main$2), {
key: 0,
name: "arrowRight",
color: "#666",
iconStyle: { width: "1em", height: "1em" }
})) : createCommentVNode("", true)
], 36)) : createCommentVNode("", true),
_ctx.showBottom ? (openBlock(), createElementBlock("div", {
key: 2,
class: "bottom separator separator-horizontal",
style: normalizeStyle(unref(bottomStyleAttrs)),
onMouseenter: _cache[4] || (_cache[4] = ($event) => mouseEventFn("bottom", true)),
onMouseout: _cache[5] || (_cache[5] = ($event) => mouseEventFn("bottom", false)),
ref_key: "bottomRef",
ref: bottomRef
}, [
!_ctx.bottomStyle ? (openBlock(), createBlock(unref(_sfc_main$2), {
key: 0,
name: "arrowRight",
color: "#666",
iconStyle: { width: "1em", height: "1em" }
})) : createCommentVNode("", true)
], 36)) : createCommentVNode("", true),
_ctx.showRight ? (openBlock(), createElementBlock("div", {
key: 3,
class: "right separator separator-vertical",
style: normalizeStyle(unref(rightStyleAttrs)),
onMouseenter: _cache[6] || (_cache[6] = ($event) => mouseEventFn("right", true)),
onMouseout: _cache[7] || (_cache[7] = ($event) => mouseEventFn("right", false)),
ref_key: "rightRef",
ref: rightRef
}, [
!_ctx.rightStyle ? (openBlock(), createBlock(unref(_sfc_main$2), {
key: 0,
name: "arrowRight",
color: "#666",
iconStyle: { width: "1em", height: "1em" }
})) : createCommentVNode("", true)
], 36)) : createCommentVNode("", true),
renderSlot(_ctx.$slots, "default", {}, void 0, true)
], 36);
};
}
});
const MarginLabel = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c1ddda83"]]);
const components = {
SvgIcon: _sfc_main$2,
ADraggableMain,
MarginLabel
};
const index = {
install(app) {
Object.keys(components).forEach((component) => {
app.component(component, components[component]);
});
}
};
export {
ADraggableMain,
MarginLabel,
_sfc_main$2 as SvgIcon,
index as default
};