Uploader.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. var __create = Object.create;
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  4. var __getOwnPropNames = Object.getOwnPropertyNames;
  5. var __getProtoOf = Object.getPrototypeOf;
  6. var __hasOwnProp = Object.prototype.hasOwnProperty;
  7. var __export = (target, all) => {
  8. for (var name2 in all)
  9. __defProp(target, name2, { get: all[name2], enumerable: true });
  10. };
  11. var __copyProps = (to, from, except, desc) => {
  12. if (from && typeof from === "object" || typeof from === "function") {
  13. for (let key of __getOwnPropNames(from))
  14. if (!__hasOwnProp.call(to, key) && key !== except)
  15. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  16. }
  17. return to;
  18. };
  19. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  20. // If the importer is in node compatibility mode or this is not an ESM
  21. // file that has been converted to a CommonJS file using a Babel-
  22. // compatible transform (i.e. "__esModule" has not been set), then set
  23. // "default" to the CommonJS "module.exports" for node compatibility.
  24. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  25. mod
  26. ));
  27. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  28. var stdin_exports = {};
  29. __export(stdin_exports, {
  30. default: () => stdin_default,
  31. uploaderProps: () => uploaderProps
  32. });
  33. module.exports = __toCommonJS(stdin_exports);
  34. var import_vue = require("vue");
  35. var import_utils = require("../utils");
  36. var import_utils2 = require("./utils");
  37. var import_use = require("@vant/use");
  38. var import_use_expose = require("../composables/use-expose");
  39. var import_icon = require("../icon");
  40. var import_image_preview = require("../image-preview");
  41. var import_UploaderPreviewItem = __toESM(require("./UploaderPreviewItem"));
  42. const uploaderProps = {
  43. name: (0, import_utils.makeNumericProp)(""),
  44. accept: (0, import_utils.makeStringProp)("image/*"),
  45. capture: String,
  46. multiple: Boolean,
  47. disabled: Boolean,
  48. readonly: Boolean,
  49. lazyLoad: Boolean,
  50. maxCount: (0, import_utils.makeNumericProp)(Infinity),
  51. imageFit: (0, import_utils.makeStringProp)("cover"),
  52. resultType: (0, import_utils.makeStringProp)("dataUrl"),
  53. uploadIcon: (0, import_utils.makeStringProp)("photograph"),
  54. uploadText: String,
  55. deletable: import_utils.truthProp,
  56. reupload: Boolean,
  57. afterRead: Function,
  58. showUpload: import_utils.truthProp,
  59. modelValue: (0, import_utils.makeArrayProp)(),
  60. beforeRead: Function,
  61. beforeDelete: Function,
  62. previewSize: [Number, String, Array],
  63. previewImage: import_utils.truthProp,
  64. previewOptions: Object,
  65. previewFullImage: import_utils.truthProp,
  66. maxSize: {
  67. type: [Number, String, Function],
  68. default: Infinity
  69. }
  70. };
  71. var stdin_default = (0, import_vue.defineComponent)({
  72. name: import_utils2.name,
  73. props: uploaderProps,
  74. emits: ["delete", "oversize", "clickUpload", "closePreview", "clickPreview", "clickReupload", "update:modelValue"],
  75. setup(props, {
  76. emit,
  77. slots
  78. }) {
  79. const inputRef = (0, import_vue.ref)();
  80. const urls = [];
  81. const reuploadIndex = (0, import_vue.ref)(-1);
  82. const isReuploading = (0, import_vue.ref)(false);
  83. const getDetail = (index = props.modelValue.length) => ({
  84. name: props.name,
  85. index
  86. });
  87. const resetInput = () => {
  88. if (inputRef.value) {
  89. inputRef.value.value = "";
  90. }
  91. };
  92. const onAfterRead = (items) => {
  93. resetInput();
  94. if ((0, import_utils2.isOversize)(items, props.maxSize)) {
  95. if (Array.isArray(items)) {
  96. const result = (0, import_utils2.filterFiles)(items, props.maxSize);
  97. items = result.valid;
  98. emit("oversize", result.invalid, getDetail());
  99. if (!items.length) {
  100. return;
  101. }
  102. } else {
  103. emit("oversize", items, getDetail());
  104. return;
  105. }
  106. }
  107. items = (0, import_vue.reactive)(items);
  108. if (reuploadIndex.value > -1) {
  109. const arr = [...props.modelValue];
  110. arr.splice(reuploadIndex.value, 1, items);
  111. emit("update:modelValue", arr);
  112. reuploadIndex.value = -1;
  113. } else {
  114. emit("update:modelValue", [...props.modelValue, ...(0, import_utils.toArray)(items)]);
  115. }
  116. if (props.afterRead) {
  117. props.afterRead(items, getDetail());
  118. }
  119. };
  120. const readFile = (files) => {
  121. const {
  122. maxCount,
  123. modelValue,
  124. resultType
  125. } = props;
  126. if (Array.isArray(files)) {
  127. const remainCount = +maxCount - modelValue.length;
  128. if (files.length > remainCount) {
  129. files = files.slice(0, remainCount);
  130. }
  131. Promise.all(files.map((file) => (0, import_utils2.readFileContent)(file, resultType))).then((contents) => {
  132. const fileList = files.map((file, index) => {
  133. const result = {
  134. file,
  135. status: "",
  136. message: "",
  137. objectUrl: URL.createObjectURL(file)
  138. };
  139. if (contents[index]) {
  140. result.content = contents[index];
  141. }
  142. return result;
  143. });
  144. onAfterRead(fileList);
  145. });
  146. } else {
  147. (0, import_utils2.readFileContent)(files, resultType).then((content) => {
  148. const result = {
  149. file: files,
  150. status: "",
  151. message: "",
  152. objectUrl: URL.createObjectURL(files)
  153. };
  154. if (content) {
  155. result.content = content;
  156. }
  157. onAfterRead(result);
  158. });
  159. }
  160. };
  161. const onChange = (event) => {
  162. const {
  163. files
  164. } = event.target;
  165. if (props.disabled || !files || !files.length) {
  166. return;
  167. }
  168. const file = files.length === 1 ? files[0] : [].slice.call(files);
  169. if (props.beforeRead) {
  170. const response = props.beforeRead(file, getDetail());
  171. if (!response) {
  172. resetInput();
  173. return;
  174. }
  175. if ((0, import_utils.isPromise)(response)) {
  176. response.then((data) => {
  177. if (data) {
  178. readFile(data);
  179. } else {
  180. readFile(file);
  181. }
  182. }).catch(resetInput);
  183. return;
  184. }
  185. }
  186. readFile(file);
  187. };
  188. let imagePreview;
  189. const onClosePreview = () => emit("closePreview");
  190. const previewImage = (item) => {
  191. if (props.previewFullImage) {
  192. const imageFiles = props.modelValue.filter(import_utils2.isImageFile);
  193. const images = imageFiles.map((item2) => {
  194. if (item2.objectUrl && !item2.url && item2.status !== "failed") {
  195. item2.url = item2.objectUrl;
  196. urls.push(item2.url);
  197. }
  198. return item2.url;
  199. }).filter(Boolean);
  200. imagePreview = (0, import_image_preview.showImagePreview)((0, import_utils.extend)({
  201. images,
  202. startPosition: imageFiles.indexOf(item),
  203. onClose: onClosePreview
  204. }, props.previewOptions));
  205. }
  206. };
  207. const closeImagePreview = () => {
  208. if (imagePreview) {
  209. imagePreview.close();
  210. }
  211. };
  212. const deleteFile = (item, index) => {
  213. const fileList = props.modelValue.slice(0);
  214. fileList.splice(index, 1);
  215. emit("update:modelValue", fileList);
  216. emit("delete", item, getDetail(index));
  217. };
  218. const reuploadFile = (index) => {
  219. isReuploading.value = true;
  220. reuploadIndex.value = index;
  221. (0, import_vue.nextTick)(() => chooseFile());
  222. };
  223. const onInputClick = () => {
  224. if (!isReuploading.value) {
  225. reuploadIndex.value = -1;
  226. }
  227. isReuploading.value = false;
  228. };
  229. const renderPreviewItem = (item, index) => {
  230. const needPickData = ["imageFit", "deletable", "reupload", "previewSize", "beforeDelete"];
  231. const previewData = (0, import_utils.extend)((0, import_utils.pick)(props, needPickData), (0, import_utils.pick)(item, needPickData, true));
  232. return (0, import_vue.createVNode)(import_UploaderPreviewItem.default, (0, import_vue.mergeProps)({
  233. "item": item,
  234. "index": index,
  235. "onClick": () => emit(props.reupload ? "clickReupload" : "clickPreview", item, getDetail(index)),
  236. "onDelete": () => deleteFile(item, index),
  237. "onPreview": () => previewImage(item),
  238. "onReupload": () => reuploadFile(index)
  239. }, (0, import_utils.pick)(props, ["name", "lazyLoad"]), previewData), (0, import_utils.pick)(slots, ["preview-cover", "preview-delete"]));
  240. };
  241. const renderPreviewList = () => {
  242. if (props.previewImage) {
  243. return props.modelValue.map(renderPreviewItem);
  244. }
  245. };
  246. const onClickUpload = (event) => emit("clickUpload", event);
  247. const renderUpload = () => {
  248. const lessThanMax = props.modelValue.length < +props.maxCount;
  249. const Input = props.readonly ? null : (0, import_vue.createVNode)("input", {
  250. "ref": inputRef,
  251. "type": "file",
  252. "class": (0, import_utils2.bem)("input"),
  253. "accept": props.accept,
  254. "capture": props.capture,
  255. "multiple": props.multiple && reuploadIndex.value === -1,
  256. "disabled": props.disabled,
  257. "onChange": onChange,
  258. "onClick": onInputClick
  259. }, null);
  260. if (slots.default) {
  261. return (0, import_vue.withDirectives)((0, import_vue.createVNode)("div", {
  262. "class": (0, import_utils2.bem)("input-wrapper"),
  263. "onClick": onClickUpload
  264. }, [slots.default(), Input]), [[import_vue.vShow, lessThanMax]]);
  265. }
  266. return (0, import_vue.withDirectives)((0, import_vue.createVNode)("div", {
  267. "class": (0, import_utils2.bem)("upload", {
  268. readonly: props.readonly
  269. }),
  270. "style": (0, import_utils.getSizeStyle)(props.previewSize),
  271. "onClick": onClickUpload
  272. }, [(0, import_vue.createVNode)(import_icon.Icon, {
  273. "name": props.uploadIcon,
  274. "class": (0, import_utils2.bem)("upload-icon")
  275. }, null), props.uploadText && (0, import_vue.createVNode)("span", {
  276. "class": (0, import_utils2.bem)("upload-text")
  277. }, [props.uploadText]), Input]), [[import_vue.vShow, props.showUpload && lessThanMax]]);
  278. };
  279. const chooseFile = () => {
  280. if (inputRef.value && !props.disabled) {
  281. inputRef.value.click();
  282. }
  283. };
  284. (0, import_vue.onBeforeUnmount)(() => {
  285. urls.forEach((url) => URL.revokeObjectURL(url));
  286. });
  287. (0, import_use_expose.useExpose)({
  288. chooseFile,
  289. reuploadFile,
  290. closeImagePreview
  291. });
  292. (0, import_use.useCustomFieldValue)(() => props.modelValue);
  293. return () => (0, import_vue.createVNode)("div", {
  294. "class": (0, import_utils2.bem)()
  295. }, [(0, import_vue.createVNode)("div", {
  296. "class": (0, import_utils2.bem)("wrapper", {
  297. disabled: props.disabled
  298. })
  299. }, [renderPreviewList(), renderUpload()])]);
  300. }
  301. });