Uploader.js 9.5 KB

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