mealcomes
Version:
MealComes 用于学习前端的组件库
591 lines (590 loc) • 14 kB
JavaScript
import { c as j, w as X } from "./utils-aznwSRCL.mjs";
import { defineComponent as D, ref as P, createElementBlock as L, openBlock as k, withModifiers as S, normalizeClass as B, unref as b, renderSlot as A, shallowRef as z, computed as q, withKeys as G, createBlock as V, createElementVNode as W, withCtx as M, mergeProps as H, watch as x, createVNode as J } from "vue";
const Q = ["text", "picture", "picture-card"];
let Y = 1;
const Z = () => Date.now() + Y++, N = {
/**
* 文件列表
*/
fileList: {
type: Array,
default: () => []
},
/**
* 上传目标地址
*/
action: {
type: String,
default: ""
},
/**
* 是否可以多上传
*/
multiple: {
type: Boolean,
default: !1
},
/**
* 上传的文件字段名
*/
name: {
type: String,
default: "file"
},
/**
* 可接受的文件类型
*/
accept: {
type: String,
default: ""
},
/**
* 请求方法
*/
method: {
type: String,
default: "post"
},
/**
* 请求头
*/
headers: {
type: Object,
default: () => ({})
},
/**
* 上传时附带的额外参数
*/
data: {
type: Object,
default: () => ({})
},
/**
* 是否自动上传文件
*/
autoUpload: {
type: Boolean,
default: !0
},
/**
* 文件列表的类型
*/
listType: {
type: String,
values: Q,
default: "text"
},
/**
* 允许上传文件的最大数量
*/
limit: {
type: Number
},
/**
* 是否启用拖拽上传
*/
drag: {
type: Boolean,
default: !1
},
/**
* 是否支持上传文件夹
*/
directory: {
type: Boolean,
default: !1
},
/**
* 是否禁用
*/
disabled: {
type: Boolean,
default: !1
}
}, O = {
...N,
/**
* 上传文件之前的钩子
*/
beforeUpload: {
type: Function,
default: () => {
}
},
/**
* 点击文件列表中已上传的文件时的钩子
*/
onPreview: {
type: Function,
default: () => {
}
},
/**
* 文件状态改变钩子, 添加文件、上传成功和上传失败时都会被调用
*/
onChange: {
type: Function,
default: () => {
}
},
/**
* 删除文件之前的钩子
*/
beforeRemove: {
type: Function,
default: () => {
}
},
/**
* 文件上传时的钩子
*/
onProgress: {
type: Function,
default: () => {
}
},
/**
* 文件列表移除文件时的钩子
*/
onRemove: {
type: Function,
default: () => {
}
},
/**
* 文件上传成功时的钩子
*/
onSuccess: {
type: Function,
default: () => {
}
},
/**
* 文件上传失败时的钩子
*/
onError: {
type: Function,
default: () => {
}
},
/**
* 当超出限制时,执行的钩子函数
*/
onExceed: {
type: Function,
default: () => {
}
}
}, ee = {
...N,
beforeUpload: O.beforeUpload,
onStart: {
type: Function,
default: () => {
}
},
onProgress: {
type: Function,
default: () => {
}
},
onRemove: {
type: Function,
default: () => {
}
},
onSuccess: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: Function,
default: () => {
}
},
onError: {
type: Function,
default: () => {
}
},
onExceed: {
type: Function,
default: () => {
}
}
}, te = {
directory: {
type: Boolean,
default: !1
},
accept: {
type: String,
default: ""
},
disabled: {
type: Boolean,
default: !1
}
}, re = {
/**
* 拖拽上传文件事件
*/
file: (n) => Array.isArray(n)
}, I = (n, a) => {
if (n && a) {
const c = Array.isArray(a) ? a : a.split(","), e = n.name || "", i = n.type || "", l = i.replace(/\/.*$/, "");
return c.some((r) => {
const d = r.trim();
if (/^\*(\/\*)?$/.test(r))
return !0;
if (d.charAt(0) === ".") {
const g = e.toLowerCase(), v = d.toLowerCase();
let p = [v];
return (v === ".jpg" || v === ".jpeg") && (p = [".jpg", ".jpeg"]), p.some((o) => g.endsWith(o));
}
return /\/\*$/.test(d) ? l === d.replace(/\/.*$/, "") : i === d ? !0 : /^\w+$/.test(d) ? (console.warn(
`Upload takes an invalidate 'accept' type '${d}'.Skip for check.`
), !0) : !1;
});
}
return !0;
};
function K(n) {
if (!n) return Promise.reject();
const a = n.createReader(), c = [], e = (i) => {
const l = [".DS_Store", ".git", "desktop.ini"];
return i.name.startsWith(".") || l.includes(i.name);
};
return new Promise((i) => {
const l = () => {
a.readEntries(async (r) => {
if (r.length === 0) {
i(c);
return;
}
for (const d of r)
if (d.isFile)
await new Promise((g) => {
d.file((v) => {
e(v) || c.push(v), g();
});
});
else if (d.isDirectory) {
const g = await K(
d
);
c.push(...g);
}
l();
});
};
l();
});
}
const oe = /* @__PURE__ */ D({
name: "mc-upload-dragger",
__name: "upload-dragger",
props: te,
emits: re,
setup(n, { emit: a }) {
const c = a, e = n, i = j("upload"), l = P(!1), r = (p) => new Promise((o) => {
K(p).then((s) => {
o(s);
}).catch((s) => {
console.warn("read directory error: ", s.message);
});
}), d = async (p) => {
var t;
if (e.disabled) return;
l.value = !1, p.stopPropagation();
const o = Array.from(p.dataTransfer.files), s = [];
if (e.directory) {
const f = p.dataTransfer.items || [];
for (let m = 0; m < o.length; m++) {
const y = f[m], h = (t = y == null ? void 0 : y.webkitGetAsEntry) == null ? void 0 : t.call(y);
if (h) {
const E = await r(
h
);
s.push(...E);
} else
console.warn(
"API webkitGetAsEntry is unsupported in you Browser"
), alert("当前浏览器不支持拖拽读取文件夹!");
}
} else
s.push(...o);
const u = s.filter(
(f) => I(f, e.accept)
);
c("file", u);
}, g = () => {
e.disabled || (l.value = !0);
}, v = (p) => {
p.currentTarget.contains(p.relatedTarget) || (l.value = !1);
};
return (p, o) => (k(), L("div", {
class: B([b(i).b("dragger"), b(i).is("dragover", l.value)]),
onDrop: S(d, ["prevent"]),
onDragover: S(g, ["prevent"]),
onDragleave: S(v, ["prevent"])
}, [
A(p.$slots, "default")
], 34));
}
});
class ne extends Error {
constructor(a, c, e, i) {
super(a), this.name = "UploadAjaxError", this.status = c, this.method = e, this.url = i;
}
}
function U(n, a, c) {
let e;
return c.response ? e = `${c.response.error || c.response}` : c.responseText ? e = `${c.responseText}` : e = `fail to ${a.method} ${n} ${c.status}`, new ne(e, c.status, a.method, n);
}
function ae(n) {
const a = n.responseText || n.response;
if (!a)
return a;
try {
return JSON.parse(a);
} catch {
return a;
}
}
function se(n) {
if (typeof XMLHttpRequest > "u")
throw new Error("XMLHttpRequest is undefined");
const a = new XMLHttpRequest(), c = n.action;
a.upload && a.upload.addEventListener("progress", (l) => {
const r = l;
r.percent = l.total > 0 ? l.loaded / l.total * 100 : 0, n.onProgress(r);
});
const e = new FormData();
if (n.data)
for (const [l, r] of Object.entries(n.data))
Array.isArray(r) && r.length ? e.append(l, ...r) : e.append(l, r);
e.append(n.filename, n.file, n.file.name), a.onerror = () => {
n.onError(U(c, n, a));
}, a.onload = () => {
if (a.status < 200 || a.status >= 300)
return n.onError(U(c, n, a));
n.onSuccess(ae(a));
}, a.open(n.method, c, !0);
const i = n.headers || {};
if (i instanceof Headers)
i.forEach((l, r) => a.setRequestHeader(r, l));
else
for (const [l, r] of Object.entries(i))
a.setRequestHeader(l, String(r));
return a.send(e), a;
}
const le = ["onKeydown"], ce = ["name", "accept", "multiple"], ue = /* @__PURE__ */ D({
name: "mc-upload-content",
inheritAttrs: !1,
__name: "upload-content",
props: ee,
setup(n, { expose: a }) {
const c = j("upload"), e = n, i = P(), l = z(
{}
), r = q(
() => e.directory ? { directory: "directory", webkitdirectory: "webkitdirectory" } : {}
), d = (t) => {
if (t.length === 0) return;
const { autoUpload: f, limit: m, fileList: y, multiple: h, onStart: E, onExceed: F } = e;
if (m && y.length + t.length > m) {
F(t, y);
return;
}
h || (t = t.slice(0, 1));
for (const $ of t) {
const w = $;
w.uid = Z(), E(w), f && g(w);
}
}, g = async (t) => {
if (i.value.value = "", !e.beforeUpload)
return v(t);
let f;
try {
f = await e.beforeUpload(t);
} catch {
f = !1;
}
if (f === !1) {
e.onRemove(t);
return;
}
v(t);
}, v = async (t) => {
const {
headers: f,
data: m,
method: y,
name: h,
action: E,
onProgress: F,
onSuccess: $,
onError: w
} = e, { uid: T } = t, _ = {
headers: f || {},
file: t,
data: m,
method: y,
filename: h,
action: E,
onProgress: (R) => {
F(R, t);
},
onSuccess: (R) => {
$(R, t), delete l.value[T];
},
onError: (R) => {
w(R, t), delete l.value[T];
}
}, C = se(_);
l.value[T] = C, C instanceof Promise && C.then(_.onSuccess, _.onError);
}, p = (t) => {
const f = t.target.files;
if (!f) return;
const m = Array.from(f).filter(
(y) => !e.directory || I(y, e.accept)
);
d(Array.from(m));
}, o = () => {
e.disabled || (i.value.value = "", i.value.click());
}, s = () => {
o();
};
return a({
abort: (t) => {
Object.entries(l.value).filter(
t ? ([m]) => String(t.uid) === m : () => !0
).forEach(([m, y]) => {
y instanceof XMLHttpRequest && y.abort(), delete l.value[m];
});
},
upload: g
}), (t, f) => (k(), L("div", {
class: B([b(c).b(), b(c).is("drag", t.drag), b(c).is("disabled", t.disabled)]),
onClick: o,
onKeydown: G(S(s, ["self"]), ["enter", "space"])
}, [
t.drag ? (k(), V(oe, {
key: 0,
onFile: d,
disabled: t.disabled,
accept: t.accept,
directory: t.directory
}, {
default: M(() => [
A(t.$slots, "default")
]),
_: 3
}, 8, ["disabled", "accept", "directory"])) : A(t.$slots, "default", { key: 1 }),
W("input", H({
ref_key: "inputRef",
ref: i,
type: "file",
class: b(c).e("input"),
name: t.name,
accept: t.accept,
multiple: t.multiple
}, r.value, { onChange: p }), null, 16, ce)
], 42, le));
}
}), ie = /* @__PURE__ */ D({
name: "mc-upload",
__name: "upload",
props: O,
emits: {
"update:file-list": (n) => n instanceof Array
},
setup(n, { expose: a, emit: c }) {
const e = n, i = c, l = P(), r = P(e.fileList);
x(r, (o) => {
i("update:file-list", o);
});
const d = (o) => r.value.find((s) => s.uid === o.uid);
function g(o) {
var s;
(s = l.value) == null || s.abort(o);
}
function v() {
r.value.filter(({ status: o }) => o === "ready").forEach(({ raw: o }) => {
var s;
return o && ((s = l.value) == null ? void 0 : s.upload(o));
});
}
const p = q(() => ({
...e,
/**
* 正式开始往后端传文件之前会将包装后的文件信息存入 uploadFiles 列表中
*/
onStart: (o) => {
const s = {
uid: o.uid,
name: o.name,
percentage: 0,
raw: o,
size: o.size,
status: "ready"
};
if (e.listType === "picture-card" || e.listType === "picture")
try {
s.url = URL.createObjectURL(o);
} catch (u) {
console.warn(u.message), e.onError(u, s, r.value);
}
r.value = [...r.value, s], e.onChange(s, r.value);
},
onProgress: (o, s) => {
const u = d(s);
u && (e.onProgress(o, u, r.value), u.status = "uploading", u.percentage = Math.round(o.percent));
},
onSuccess: (o, s) => {
const u = d(s);
u && (u.status = "success", u.response = o, e.onSuccess(o, u, r.value), e.onChange(u, r.value));
},
onError: (o, s) => {
const u = d(s);
u && (console.error(o), u.status = "fail", r.value = r.value.filter(
(t) => t.uid !== u.uid
), e.onError(o, u, r.value), e.onChange(u, r.value));
},
onRemove: async (o) => {
const s = d(o);
if (!s) throw new Error("file to be removed not found");
const u = (t) => {
g(t), r.value = r.value.filter(
(f) => f.uid !== t.uid
), e.onRemove(t, r.value);
};
e.beforeRemove ? await e.beforeRemove(
s,
r.value
) !== !1 && u(s) : u(s);
}
}));
return a({
/** 取消上传请求 */
abort: g,
/** 上传文件列表 */
submit: v
}), (o, s) => (k(), L("div", null, [
J(ue, H({
ref_key: "uploadRef",
ref: l
}, p.value), {
default: M(() => [
A(o.$slots, "default")
]),
_: 3
}, 16)
]));
}
}), pe = X(ie);
export {
pe as M,
N as a,
O as b,
Z as g,
Q as u
};
//# sourceMappingURL=upload-DFGEOadx.mjs.map