usemodal-vue3
Version:
An easy-to-use Modal for Vue 3. Multiple modals can pop up orderly.
272 lines (271 loc) • 9.81 kB
JavaScript
import { defineComponent as V, ref as $, reactive as m, watch as Y, h as i } from "vue";
function O(e) {
return typeof e == "boolean";
}
function N(e) {
return typeof e == "number";
}
function S(e) {
return typeof e == "object" && e !== null;
}
function X(e) {
const g = m({}), d = {
currOrder: 0,
triggerTotal: 0,
list: [],
track(n) {
this.list.push(n);
},
trigger(n, l) {
if (this.triggerTotal++, this.list = this.list.map((v) => (v.name === n && (v.visible = l), v)), this.triggerTotal >= this.list.length)
if (this.currOrder < this.list.length) {
for (; this.currOrder < this.list.length && (g[this.list[this.currOrder].name] = this.list[this.currOrder].visible, !this.list[this.currOrder].visible); )
this.currOrder++;
this.currOrder = 0;
} else
this.triggerTotal = 0, this.trigger(n, l);
}
};
if (e) {
d.list = [];
for (let n in e) {
let l = {
name: n,
order: Number(e[n])
};
d.track(l);
}
d.list.sort((n, l) => n.order - l.order);
}
return function(n, l) {
return d.trigger(n, l), {
currVisible: g,
dep: d
};
};
}
const D = V({
props: {
visible: [Object, Boolean],
name: String,
mask: {
type: Boolean,
default: !0
},
maskClosable: {
type: Boolean,
default: !0
},
type: {
type: String,
default: ""
},
modalClass: {
type: String,
default: "modal-vue3-wrap"
},
width: {
type: [String, Number],
default: 500
},
offsetTop: {
type: [String, Number],
default: 100
},
zIndex: {
type: [String, Number],
default: 1e3
},
title: {
type: String,
default: "Title"
},
animation: {
type: Boolean,
default: !0
},
closable: {
type: Boolean,
default: !0
},
draggable: {
type: [Boolean, Object],
default: !1
},
cancelButton: {
type: Object,
default: () => ({
text: "cancel",
onclick: null,
loading: !1
})
},
okButton: {
type: Object,
default: () => ({
text: "ok",
onclick: null,
loading: !1
})
}
},
setup(e, { slots: g, emit: d }) {
let n;
const l = e.name, v = typeof e.width == "string" ? e.width : `${e.width}px`, C = typeof e.offsetTop == "string" ? e.offsetTop : `${e.offsetTop}px`, T = $(null), h = $(null);
let j = null, x = null, o = m({
init: -15,
value: -15,
max: 0,
step: 1,
speed: 10,
linear: !1
}), b = m({
init: 0,
value: 0,
max: 360,
step: 30,
speed: 30,
linear: !0
});
const y = (t, s, u) => {
let B = s ? t.max : t.init, c = s ? t.init : t.max;
if (s ? t.value <= c : t.value >= c)
return t.linear ? t.value = B : (t.value = c, u && u()), !1;
setTimeout(() => {
s ? t.value -= t.step : t.value += t.step;
}, t.speed);
}, k = (t) => {
t && n.list.length > 0 && S(e.visible) ? n.trigger(t, !1) : d("update:visible", !1);
}, M = (t) => {
!e.maskClosable || !e.mask || t.target === T.value && k(l);
};
let a = m({
value: !1,
target: ""
});
const E = (t, s) => {
const u = t[s];
(!u.loading || u.loading && !a.value) && (u.onclick && typeof u.onclick == "function" ? u.onclick() : k(t.name), u.loading && (a.value = !0, a.target = s));
}, r = $(), f = m({
left: void 0,
top: void 0
}), w = (t) => {
t.preventDefault(), t.stopPropagation();
}, z = (t) => {
let s = h.value.offsetLeft, u = h.value.offsetTop, B = {
width: h.value.offsetWidth,
height: h.value.offsetHeight,
clientWidth: document.documentElement.clientWidth,
clientHeight: document.documentElement.clientHeight,
x: t.pageX - s,
y: t.pageY - u
};
r.value = B, w(t);
const c = (p) => {
if (!r.value)
return;
let W = p.pageX, H = p.pageY;
f.left = Math.min(Math.max(W - r.value.x, 0), r.value.clientWidth - r.value.width), f.top = Math.min(Math.max(H - r.value.y, 0), r.value.clientHeight - r.value.height), w(p);
}, L = (p) => {
!r.value || (r.value = void 0, w(p), document.removeEventListener("pointermove", c), document.removeEventListener("pointerup", L));
};
document.addEventListener("pointermove", c), document.addEventListener("pointerup", L);
};
return Y(() => e.draggable, (t) => {
S(t) && t.addEventListener("pointerdown", z);
}), () => {
if (g.default) {
let t;
return O(e.visible) ? t = e.visible : (t = e.visible.currVisible[l], n = e.visible.dep), t ? (a.value && y(b), e.animation === !1 ? o.value = o.max : (j != l && (j = l, o.value = o.init), o.speed = 5, y(o)), o.value >= o.max && !r.value && x != l && (x = l, d("onVisible"))) : (x == l || !l) && (e.animation === !1 ? t = !1 : (t = !0, o.speed = 2, y(o, !0, () => {
t = !1, x = null, a.value = !1, d("onUnVisible");
}))), t ? i("div", {
class: e.modalClass
}, [
e.mask ? i("div", {
class: "modal-vue3-mask",
style: `width:100%;height:100%;position:fixed;left:0;top:0;background-color:rgba(0, 0, 0, 0.25);z-index:${e.zIndex - 1};`
}) : null,
i("div", {
ref: T,
style: `position:fixed;left:0;right:0;top:0;bottom:0;margin: 0 auto;z-index:${e.zIndex};overflow:auto;outline:0;`,
onclick: (s) => {
M(s);
}
}, [
i(
"div",
{
ref: h,
class: "modal-vue3-content",
style: `width:${v};position:relative;top:${N(f.top) ? f.top + "px" : C};left:${f.left ? f.left + "px" : ""};margin: ${N(f.left) ? "0" : "0 auto"}; ${e.type != "clean" ? "border:1px solid #f0f0f0;" : ""}overflow:auto;outline:0;box-sizing:border-box; ${e.type != "clean" ? "background-color:#fff;" : ""}border-radius:2px;transform:translateY(${o.value}px);`
},
[
e.type != "clean" ? i("div", {
class: "modal-vue3-header",
style: `padding:12px 22px;border-bottom:1px solid #f0f0f0;position:relative;${e.draggable && O(e.draggable) ? "cursor:move;" : ""}`,
onpointerdown: e.draggable && O(e.draggable) ? z : null
}, [
i("div", null, e.title),
e.closable ? i("div", {
style: "width:20px;height:16px;cursor:pointer;position:absolute;top:15px;right:15px;font-size: 20px;",
onclick: () => {
k(l);
}
}, [
i("div", {
style: "width:14px;height:1px;position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;background-color:#999;transform:rotate(45deg);"
}, ""),
i("div", {
style: "width:14px;height:1px;position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;background-color:#999;transform:rotate(-45deg);"
}, "")
]) : null
]) : null,
i("div", {
class: "modal-vue3-body",
style: e.type != "clean" ? "padding: 14px 22px" : ""
}, g.default()),
e.type != "clean" ? i("div", {
class: "modal-vue3-footer",
style: "padding: 12px 22px;display:flex;justify-content:flex-end;align-items:center;border-top:1px solid #f0f0f0;"
}, [
i("div", {
class: "modal-vue3-footer-cancel",
style: `margin-right: 20px;height:30px;padding:0 8px;border-radius:2px;border: 1px solid #d9d9d9;display:flex;justify-content:center;align-items:center;cursor:pointer;position:relative;${a.value && a.target === "cancelButton" ? "opacity:.6;" : ""}`,
onclick: () => {
E(e, "cancelButton");
}
}, [
a.value && a.target === "cancelButton" ? i("span", {
style: `width: 10px;height:10px;margin-right:5px;border:1px solid #666;border-radius:50%;border-top:1px solid transparent; transform:rotate(${b.value}deg);`
}) : null,
i("div", {
style: "min-width:44px;text-align:center;"
}, e.cancelButton.text || "cancel")
]),
i("div", {
class: "modal-vue3-footer-ok",
style: `height:30px;padding: 0 8px;border-radius:2px;display:flex;justify-content:center;align-items:center;background-color:#4395ff;color:#fff;cursor:pointer;position:relative;${a.value && a.target === "okButton" ? "opacity:.6;" : ""}`,
onclick: () => {
E(e, "okButton");
}
}, [
a.value && a.target === "okButton" ? i("span", {
style: `width: 10px;height:10px;margin-right:5px;border:1px solid #fff;border-radius:50%;border-top:1px solid transparent; transform:rotate(${b.value}deg);`
}) : null,
i("div", {
style: "min-width:44px;text-align:center;"
}, e.okButton.text || "ok")
])
]) : null
]
)
])
]) : null;
}
};
}
});
export {
D as Modal,
X as useModal
};