@gyenno/nutui-taro
Version:
京东风格的轻量级移动端 Vue2、Vue3 组件库(支持小程序开发)
592 lines (591 loc) • 21.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { reactive, computed, resolveComponent, openBlock, createElementBlock, normalizeClass, renderSlot, createTextVNode, createBlock, createCommentVNode, Fragment, renderList, createElementVNode, toDisplayString, createVNode } from "vue";
import { c as createComponent } from "./component-25dcca32.js";
import { f as funInterceptor } from "./Interceptor-157a0193.js";
import Progress from "./Progress.js";
import Button from "./Button.js";
import Taro from "@tarojs/taro";
import { Photograph, Failure, Loading, Del, Link } from "@nutui/icons-vue-taro";
import { _ as _export_sfc } from "./_plugin-vue_export-helper-cc2b3d55.js";
import "../locale/lang";
class UploadOptions {
constructor() {
__publicField(this, "url", "");
__publicField(this, "name", "file");
__publicField(this, "fileType", "image");
__publicField(this, "formData");
__publicField(this, "sourceFile");
__publicField(this, "method", "post");
__publicField(this, "xhrState", 200);
__publicField(this, "timeout", 30 * 1e3);
__publicField(this, "headers", {});
__publicField(this, "withCredentials", false);
__publicField(this, "onStart");
__publicField(this, "taroFilePath");
__publicField(this, "onProgress");
__publicField(this, "onSuccess");
__publicField(this, "onFailure");
__publicField(this, "beforeXhrUpload");
}
}
class Uploader {
constructor(options) {
__publicField(this, "options");
this.options = options;
}
upload() {
var _a;
const options = this.options;
const xhr = new XMLHttpRequest();
xhr.timeout = options.timeout;
if (xhr.upload) {
xhr.upload.addEventListener(
"progress",
(e) => {
var _a2;
(_a2 = options.onProgress) == null ? void 0 : _a2.call(options, e, options);
},
false
);
xhr.onreadystatechange = () => {
var _a2, _b;
if (xhr.readyState === 4) {
if (xhr.status == options.xhrState) {
(_a2 = options.onSuccess) == null ? void 0 : _a2.call(options, xhr.responseText, options);
} else {
(_b = options.onFailure) == null ? void 0 : _b.call(options, xhr.responseText, options);
}
}
};
xhr.withCredentials = options.withCredentials;
xhr.open(options.method, options.url, true);
for (const [key, value] of Object.entries(options.headers)) {
xhr.setRequestHeader(key, value);
}
(_a = options.onStart) == null ? void 0 : _a.call(options, options);
if (options.beforeXhrUpload) {
options.beforeXhrUpload(xhr, options);
} else {
xhr.send(options.formData);
}
} else {
console.warn("浏览器不支持 XMLHttpRequest");
}
}
}
class UploaderTaro extends Uploader {
constructor(options) {
super(options);
}
uploadTaro(uploadFile, env) {
var _a;
const options = this.options;
if (env === "WEB") {
this.upload();
} else {
if (options.beforeXhrUpload) {
options.beforeXhrUpload(uploadFile, options);
} else {
const uploadTask = uploadFile({
url: options.url,
filePath: options.taroFilePath,
fileType: options.fileType,
header: {
"Content-Type": "multipart/form-data",
...options.headers
},
//
formData: options.formData,
name: options.name,
success(response) {
var _a2, _b;
if (options.xhrState == response.statusCode) {
(_a2 = options.onSuccess) == null ? void 0 : _a2.call(options, response, options);
} else {
(_b = options.onFailure) == null ? void 0 : _b.call(options, response, options);
}
},
fail(e) {
var _a2;
(_a2 = options.onFailure) == null ? void 0 : _a2.call(options, e, options);
}
});
(_a = options.onStart) == null ? void 0 : _a.call(options, options);
uploadTask.progress((res) => {
var _a2;
(_a2 = options.onProgress) == null ? void 0 : _a2.call(options, res, options);
});
}
}
}
}
const { translate: translate$1 } = createComponent("uploader");
class FileItem {
constructor() {
__publicField(this, "status", "ready");
__publicField(this, "message", translate$1("ready"));
__publicField(this, "uid", (/* @__PURE__ */ new Date()).getTime().toString());
__publicField(this, "name");
__publicField(this, "url");
__publicField(this, "type");
__publicField(this, "path");
__publicField(this, "percentage", 0);
__publicField(this, "formData", {});
}
}
const { componentName, create, translate } = createComponent("uploader");
const _sfc_main = create({
components: {
[Progress.name]: Progress,
[Button.name]: Button,
Photograph,
Failure,
Loading,
Del,
Link
},
props: {
name: { type: String, default: "file" },
url: { type: String, default: "" },
sizeType: {
type: Array,
default: () => ["original", "compressed"]
},
sourceType: {
type: Array,
default: () => ["album", "camera"]
},
mediaType: {
type: Array,
default: () => ["image", "video", "mix"]
},
camera: {
type: String,
default: "back"
},
timeout: { type: [Number, String], default: 1e3 * 30 },
// defaultFileList: { type: Array, default: () => new Array<FileItem>() },
fileList: { type: Array, default: () => [] },
isPreview: { type: Boolean, default: true },
// picture、list
listType: { type: String, default: "picture" },
isDeletable: { type: Boolean, default: true },
method: { type: String, default: "post" },
capture: { type: Boolean, default: false },
maximize: { type: [Number, String], default: Number.MAX_VALUE },
maximum: { type: [Number, String], default: 9 },
clearInput: { type: Boolean, default: true },
accept: { type: String, default: "*" },
headers: { type: Object, default: {} },
data: { type: Object, default: {} },
xhrState: { type: [Number, String], default: 200 },
multiple: { type: Boolean, default: true },
disabled: { type: Boolean, default: false },
autoUpload: { type: Boolean, default: true },
maxDuration: { type: Number, default: 10 },
beforeXhrUpload: {
type: Function,
default: null
},
beforeDelete: {
type: Function,
default: (file, files) => {
return true;
}
},
onChange: { type: Function }
},
emits: [
"start",
"progress",
"oversize",
"success",
"failure",
"change",
"delete",
"update:fileList",
"file-item-click"
],
setup(props, { emit }) {
const fileList = reactive(props.fileList);
let uploadQueue = [];
const classes = computed(() => {
const prefixCls = componentName;
return {
[prefixCls]: true
};
});
const chooseImage = () => {
if (props.disabled) {
return;
}
if (Taro.getEnv() == "WEB") {
let el = document.getElementById("taroChooseImage");
if (el) {
el == null ? void 0 : el.setAttribute("accept", props.accept);
} else {
const obj = document.createElement("input");
obj.setAttribute("type", "file");
obj.setAttribute("id", "taroChooseImage");
obj.setAttribute("accept", props.accept);
obj.setAttribute("style", "position: fixed; top: -4000px; left: -3000px; z-index: -300;");
document.body.appendChild(obj);
}
}
if (Taro.getEnv() == "WEAPP") {
Taro.chooseMedia({
/** 最多可以选择的文件个数 */
count: props.multiple ? props.maximum * 1 - props.fileList.length : 1,
/** 文件类型 */
mediaType: props.mediaType,
/** 图片和视频选择的来源 */
sourceType: props.sourceType,
/** 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 30s 之间 */
maxDuration: props.maxDuration,
/** 仅对 mediaType 为 image 时有效,是否压缩所选文件 */
sizeType: [],
/** 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 */
camera: props.camera,
/** 接口调用失败的回调函数 */
fail: (res) => {
emit("failure", res);
},
/** 接口调用成功的回调函数 */
success: onChangeMedia
});
} else {
Taro.chooseImage({
// 选择数量
count: props.multiple ? props.maximum * 1 - props.fileList.length : 1,
// 可以指定是原图还是压缩图,默认二者都有
sizeType: props.sizeType,
sourceType: props.sourceType,
success: onChangeImage,
fail: (res) => {
emit("failure", res);
}
});
}
};
const onChangeMedia = (res) => {
const { type, tempFiles } = res;
const _files = filterFiles(tempFiles);
readFile(_files);
emit("change", {
fileList
});
};
const onChangeImage = (res) => {
const { tempFilePaths, tempFiles } = res;
const _files = filterFiles(tempFiles);
readFile(_files);
emit("change", {
fileList
});
};
const fileItemClick = (fileItem) => {
emit("file-item-click", { fileItem });
};
const executeUpload = (fileItem, index) => {
const uploadOption = new UploadOptions();
uploadOption.name = props.name;
uploadOption.url = props.url;
uploadOption.fileType = fileItem.type;
uploadOption.formData = fileItem.formData;
uploadOption.timeout = props.timeout * 1;
uploadOption.method = props.method;
uploadOption.xhrState = props.xhrState;
uploadOption.method = props.method;
uploadOption.headers = props.headers;
uploadOption.taroFilePath = fileItem.path;
uploadOption.beforeXhrUpload = props.beforeXhrUpload;
uploadOption.onStart = (option) => {
fileItem.status = "ready";
fileItem.message = translate("readyUpload");
clearUploadQueue(index);
emit("start", option);
};
uploadOption.onProgress = (event, option) => {
fileItem.status = "uploading";
fileItem.message = translate("uploading");
fileItem.percentage = event.progress;
emit("progress", { event, option, percentage: fileItem.percentage });
};
uploadOption.onSuccess = (data, option) => {
fileItem.status = "success";
fileItem.message = translate("success");
emit("success", {
data,
responseText: data,
option,
fileItem
});
emit("update:fileList", fileList);
};
uploadOption.onFailure = (data, option) => {
fileItem.status = "error";
fileItem.message = translate("error");
emit("failure", {
data,
responseText: data,
option,
fileItem
});
};
let task = new UploaderTaro(uploadOption);
if (props.autoUpload) {
task.uploadTaro(Taro.uploadFile, Taro.getEnv());
} else {
uploadQueue.push(
new Promise((resolve, reject) => {
resolve(task);
})
);
}
};
const clearUploadQueue = (index = -1) => {
if (index > -1) {
uploadQueue.splice(index, 1);
} else {
uploadQueue = [];
fileList.splice(0, fileList.length);
}
};
const submit = () => {
Promise.all(uploadQueue).then((res) => {
res.forEach((i) => i.uploadTaro(Taro.uploadFile, Taro.getEnv()));
});
};
const readFile = (files) => {
files.forEach((file, index) => {
var _a, _b;
let fileType = file.type;
let filepath = file.tempFilePath || file.path;
const fileItem = reactive(new FileItem());
if (file.fileType) {
fileType = file.fileType;
} else {
const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i;
if (!fileType && (imgReg.test(filepath) || filepath.includes("data:image"))) {
fileType = "image";
}
}
fileItem.path = filepath;
fileItem.name = filepath;
fileItem.status = "ready";
fileItem.message = translate("waitingUpload");
fileItem.type = fileType;
if (Taro.getEnv() == "WEB") {
const formData = new FormData();
for (const [key, value] of Object.entries(props.data)) {
formData.append(key, value);
}
formData.append(props.name, file.originalFileObj);
fileItem.name = (_a = file.originalFileObj) == null ? void 0 : _a.name;
fileItem.type = (_b = file.originalFileObj) == null ? void 0 : _b.type;
fileItem.formData = formData;
} else {
fileItem.formData = props.data;
}
if (props.isPreview) {
fileItem.url = fileType == "video" ? file.thumbTempFilePath : filepath;
}
fileList.push(fileItem);
executeUpload(fileItem, index);
});
};
const filterFiles = (files) => {
const maximum = props.maximum * 1;
const maximize = props.maximize * 1;
const oversizes = new Array();
files = files.filter((file) => {
if (file.size > maximize) {
oversizes.push(file);
return false;
} else {
return true;
}
});
if (oversizes.length) {
emit("oversize", oversizes);
}
let currentFileLength = files.length + fileList.length;
if (currentFileLength > maximum) {
files.splice(files.length - (currentFileLength - maximum));
}
return files;
};
const deleted = (file, index) => {
fileList.splice(index, 1);
emit("delete", {
file,
fileList,
index
});
};
const onDelete = (file, index) => {
clearUploadQueue(index);
funInterceptor(props.beforeDelete, {
args: [file, fileList],
done: () => deleted(file, index)
});
};
return {
onDelete,
fileList,
classes,
chooseImage,
fileItemClick,
clearUploadQueue,
submit
};
}
});
const _hoisted_1 = {
key: 0,
class: "nut-uploader__slot"
};
const _hoisted_2 = {
key: 0,
class: "nut-uploader__preview-img"
};
const _hoisted_3 = {
key: 0,
class: "nut-uploader__preview__progress"
};
const _hoisted_4 = { class: "nut-uploader__preview__progress__msg" };
const _hoisted_5 = ["onClick"];
const _hoisted_6 = ["onClick", "src"];
const _hoisted_7 = {
key: 3,
class: "nut-uploader__preview-img__file"
};
const _hoisted_8 = ["onClick"];
const _hoisted_9 = { class: "file__name_tips" };
const _hoisted_10 = { class: "tips" };
const _hoisted_11 = {
key: 1,
class: "nut-uploader__preview-list"
};
const _hoisted_12 = ["onClick"];
const _hoisted_13 = { class: "file__name_tips" };
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_nut_button = resolveComponent("nut-button");
const _component_Failure = resolveComponent("Failure");
const _component_Loading = resolveComponent("Loading");
const _component_Link = resolveComponent("Link");
const _component_Del = resolveComponent("Del");
const _component_nut_progress = resolveComponent("nut-progress");
const _component_Photograph = resolveComponent("Photograph");
return openBlock(), createElementBlock("view", {
class: normalizeClass(_ctx.classes)
}, [
_ctx.$slots.default ? (openBlock(), createElementBlock("view", _hoisted_1, [
renderSlot(_ctx.$slots, "default"),
createTextVNode(),
Number(_ctx.maximum) - _ctx.fileList.length ? (openBlock(), createBlock(_component_nut_button, {
key: 0,
class: "nut-uploader__input",
onClick: _ctx.chooseImage
}, null, 8, ["onClick"])) : createCommentVNode("", true)
])) : createCommentVNode("", true),
createTextVNode(),
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.fileList, (item, index) => {
return openBlock(), createElementBlock("view", {
class: normalizeClass(["nut-uploader__preview", [_ctx.listType]]),
key: item.uid
}, [
_ctx.listType == "picture" && !_ctx.$slots.default ? (openBlock(), createElementBlock("view", _hoisted_2, [
item.status != "success" ? (openBlock(), createElementBlock("view", _hoisted_3, [
item.status != "ready" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
item.status == "error" ? (openBlock(), createBlock(_component_Failure, {
key: 0,
color: "#fff"
})) : (openBlock(), createBlock(_component_Loading, {
key: 1,
name: "loading",
color: "#fff"
}))
], 64)) : createCommentVNode("", true),
createTextVNode(),
createElementVNode("view", _hoisted_4, toDisplayString(item.message), 1)
])) : createCommentVNode("", true),
createTextVNode(),
_ctx.isDeletable ? (openBlock(), createElementBlock("view", {
key: 1,
class: "close",
onClick: ($event) => _ctx.onDelete(item, index)
}, [
renderSlot(_ctx.$slots, "delete-icon", {}, () => [
createVNode(_component_Failure)
])
], 8, _hoisted_5)) : createCommentVNode("", true),
createTextVNode(),
["image", "video"].includes(item.type) && item.url ? (openBlock(), createElementBlock("img", {
key: 2,
class: "nut-uploader__preview-img__c",
mode: "aspectFit",
onClick: ($event) => _ctx.fileItemClick(item),
src: item.url
}, null, 8, _hoisted_6)) : (openBlock(), createElementBlock("view", _hoisted_7, [
createElementVNode("view", {
class: "nut-uploader__preview-img__file__name",
onClick: ($event) => _ctx.fileItemClick(item)
}, [
createElementVNode("view", _hoisted_9, toDisplayString(item.name), 1)
], 8, _hoisted_8)
])),
createTextVNode(),
createElementVNode("view", _hoisted_10, toDisplayString(item.name), 1)
])) : _ctx.listType == "list" ? (openBlock(), createElementBlock("view", _hoisted_11, [
createElementVNode("view", {
class: normalizeClass(["nut-uploader__preview-img__file__name", [item.status]]),
onClick: ($event) => _ctx.fileItemClick(item)
}, [
createVNode(_component_Link, { class: "nut-uploader__preview-img__file__link" }),
createTextVNode(),
createElementVNode("view", _hoisted_13, toDisplayString(item.name), 1),
createTextVNode(),
_ctx.isDeletable ? (openBlock(), createBlock(_component_Del, {
key: 0,
color: "#808080",
class: "nut-uploader__preview-img__file__del",
onClick: ($event) => _ctx.onDelete(item, index)
}, null, 8, ["onClick"])) : createCommentVNode("", true)
], 10, _hoisted_12),
createTextVNode(),
item.status == "uploading" ? (openBlock(), createBlock(_component_nut_progress, {
key: 0,
size: "small",
percentage: item.percentage,
"stroke-color": "linear-gradient(270deg, rgba(18,126,255,1) 0%,rgba(32,147,255,1) 32.815625%,rgba(13,242,204,1) 100%)",
"show-text": false
}, null, 8, ["percentage"])) : createCommentVNode("", true)
])) : createCommentVNode("", true)
], 2);
}), 128)),
createTextVNode(),
_ctx.listType == "picture" && !_ctx.$slots.default && Number(_ctx.maximum) - _ctx.fileList.length ? (openBlock(), createElementBlock("view", {
key: 1,
class: normalizeClass(["nut-uploader__upload", [_ctx.listType]])
}, [
renderSlot(_ctx.$slots, "upload-icon", {}, () => [
createVNode(_component_Photograph, { color: "#808080" })
]),
createTextVNode(),
createVNode(_component_nut_button, {
class: normalizeClass(["nut-uploader__input", { disabled: _ctx.disabled }]),
onClick: _ctx.chooseImage
}, null, 8, ["class", "onClick"])
], 2)) : createCommentVNode("", true)
], 2);
}
const index_taro = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export {
index_taro as default
};