index.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <script>
  2. import UploadList from './upload-list';
  3. import Upload from './upload';
  4. import ElProgress from 'element-ui/packages/progress';
  5. import Migrating from 'element-ui/src/mixins/migrating';
  6. function noop() {}
  7. export default {
  8. name: 'ElUpload',
  9. mixins: [Migrating],
  10. components: {
  11. ElProgress,
  12. UploadList,
  13. Upload
  14. },
  15. provide() {
  16. return {
  17. uploader: this
  18. };
  19. },
  20. inject: {
  21. elForm: {
  22. default: ''
  23. }
  24. },
  25. props: {
  26. action: {
  27. type: String,
  28. required: true
  29. },
  30. headers: {
  31. type: Object,
  32. default() {
  33. return {};
  34. }
  35. },
  36. data: Object,
  37. multiple: Boolean,
  38. name: {
  39. type: String,
  40. default: 'file'
  41. },
  42. drag: Boolean,
  43. dragger: Boolean,
  44. withCredentials: Boolean,
  45. showFileList: {
  46. type: Boolean,
  47. default: true
  48. },
  49. accept: String,
  50. type: {
  51. type: String,
  52. default: 'select'
  53. },
  54. beforeUpload: Function,
  55. beforeRemove: Function,
  56. onRemove: {
  57. type: Function,
  58. default: noop
  59. },
  60. onChange: {
  61. type: Function,
  62. default: noop
  63. },
  64. onPreview: {
  65. type: Function
  66. },
  67. onSuccess: {
  68. type: Function,
  69. default: noop
  70. },
  71. onProgress: {
  72. type: Function,
  73. default: noop
  74. },
  75. onError: {
  76. type: Function,
  77. default: noop
  78. },
  79. fileList: {
  80. type: Array,
  81. default() {
  82. return [];
  83. }
  84. },
  85. autoUpload: {
  86. type: Boolean,
  87. default: true
  88. },
  89. listType: {
  90. type: String,
  91. default: 'text' // text,picture,picture-card
  92. },
  93. httpRequest: Function,
  94. disabled: Boolean,
  95. limit: Number,
  96. onExceed: {
  97. type: Function,
  98. default: noop
  99. }
  100. },
  101. data() {
  102. return {
  103. uploadFiles: [],
  104. dragOver: false,
  105. draging: false,
  106. tempIndex: 1
  107. };
  108. },
  109. computed: {
  110. uploadDisabled() {
  111. return this.disabled || (this.elForm || {}).disabled;
  112. }
  113. },
  114. watch: {
  115. listType(type) {
  116. if (type === 'picture-card' || type === 'picture') {
  117. this.uploadFiles = this.uploadFiles.map(file => {
  118. if (!file.url && file.raw) {
  119. try {
  120. file.url = URL.createObjectURL(file.raw);
  121. } catch (err) {
  122. console.error('[Element Error][Upload]', err);
  123. }
  124. }
  125. return file;
  126. });
  127. }
  128. },
  129. fileList: {
  130. immediate: true,
  131. handler(fileList) {
  132. this.uploadFiles = fileList.map(item => {
  133. item.uid = item.uid || (Date.now() + this.tempIndex++);
  134. item.status = item.status || 'success';
  135. return item;
  136. });
  137. }
  138. }
  139. },
  140. methods: {
  141. handleStart(rawFile) {
  142. rawFile.uid = Date.now() + this.tempIndex++;
  143. let file = {
  144. status: 'ready',
  145. name: rawFile.name,
  146. size: rawFile.size,
  147. percentage: 0,
  148. uid: rawFile.uid,
  149. raw: rawFile
  150. };
  151. if (this.listType === 'picture-card' || this.listType === 'picture') {
  152. try {
  153. file.url = URL.createObjectURL(rawFile);
  154. } catch (err) {
  155. console.error('[Element Error][Upload]', err);
  156. return;
  157. }
  158. }
  159. this.uploadFiles.push(file);
  160. this.onChange(file, this.uploadFiles);
  161. },
  162. handleProgress(ev, rawFile) {
  163. const file = this.getFile(rawFile);
  164. this.onProgress(ev, file, this.uploadFiles);
  165. file.status = 'uploading';
  166. file.percentage = ev.percent || 0;
  167. },
  168. handleSuccess(res, rawFile) {
  169. const file = this.getFile(rawFile);
  170. if (file) {
  171. file.status = 'success';
  172. file.response = res;
  173. this.onSuccess(res, file, this.uploadFiles);
  174. this.onChange(file, this.uploadFiles);
  175. }
  176. },
  177. handleError(err, rawFile) {
  178. const file = this.getFile(rawFile);
  179. const fileList = this.uploadFiles;
  180. file.status = 'fail';
  181. fileList.splice(fileList.indexOf(file), 1);
  182. this.onError(err, file, this.uploadFiles);
  183. this.onChange(file, this.uploadFiles);
  184. },
  185. handleRemove(file, raw) {
  186. if (raw) {
  187. file = this.getFile(raw);
  188. }
  189. let doRemove = () => {
  190. this.abort(file);
  191. let fileList = this.uploadFiles;
  192. fileList.splice(fileList.indexOf(file), 1);
  193. this.onRemove(file, fileList);
  194. };
  195. if (!this.beforeRemove) {
  196. doRemove();
  197. } else if (typeof this.beforeRemove === 'function') {
  198. const before = this.beforeRemove(file, this.uploadFiles);
  199. if (before && before.then) {
  200. before.then(() => {
  201. doRemove();
  202. }, noop);
  203. } else if (before !== false) {
  204. doRemove();
  205. }
  206. }
  207. },
  208. getFile(rawFile) {
  209. let fileList = this.uploadFiles;
  210. let target;
  211. fileList.every(item => {
  212. target = rawFile.uid === item.uid ? item : null;
  213. return !target;
  214. });
  215. return target;
  216. },
  217. abort(file) {
  218. this.$refs['upload-inner'].abort(file);
  219. },
  220. clearFiles() {
  221. this.uploadFiles = [];
  222. },
  223. submit() {
  224. this.uploadFiles
  225. .filter(file => file.status === 'ready')
  226. .forEach(file => {
  227. this.$refs['upload-inner'].upload(file.raw);
  228. });
  229. },
  230. getMigratingConfig() {
  231. return {
  232. props: {
  233. 'default-file-list': 'default-file-list is renamed to file-list.',
  234. 'show-upload-list': 'show-upload-list is renamed to show-file-list.',
  235. 'thumbnail-mode': 'thumbnail-mode has been deprecated, you can implement the same effect according to this case: http://element.eleme.io/#/zh-CN/component/upload#yong-hu-tou-xiang-shang-chuan'
  236. }
  237. };
  238. }
  239. },
  240. beforeDestroy() {
  241. this.uploadFiles.forEach(file => {
  242. if (file.url && file.url.indexOf('blob:') === 0) {
  243. URL.revokeObjectURL(file.url);
  244. }
  245. });
  246. },
  247. render(h) {
  248. let uploadList;
  249. if (this.showFileList) {
  250. uploadList = (
  251. <UploadList
  252. disabled={this.uploadDisabled}
  253. listType={this.listType}
  254. files={this.uploadFiles}
  255. on-remove={this.handleRemove}
  256. handlePreview={this.onPreview}>
  257. {
  258. (props) => {
  259. if (this.$scopedSlots.file) {
  260. return this.$scopedSlots.file({
  261. file: props.file
  262. });
  263. }
  264. }
  265. }
  266. </UploadList>
  267. );
  268. }
  269. const uploadData = {
  270. props: {
  271. type: this.type,
  272. drag: this.drag,
  273. action: this.action,
  274. multiple: this.multiple,
  275. 'before-upload': this.beforeUpload,
  276. 'with-credentials': this.withCredentials,
  277. headers: this.headers,
  278. name: this.name,
  279. data: this.data,
  280. accept: this.accept,
  281. fileList: this.uploadFiles,
  282. autoUpload: this.autoUpload,
  283. listType: this.listType,
  284. disabled: this.uploadDisabled,
  285. limit: this.limit,
  286. 'on-exceed': this.onExceed,
  287. 'on-start': this.handleStart,
  288. 'on-progress': this.handleProgress,
  289. 'on-success': this.handleSuccess,
  290. 'on-error': this.handleError,
  291. 'on-preview': this.onPreview,
  292. 'on-remove': this.handleRemove,
  293. 'http-request': this.httpRequest
  294. },
  295. ref: 'upload-inner'
  296. };
  297. const trigger = this.$slots.trigger || this.$slots.default;
  298. const uploadComponent = <upload {...uploadData}>{trigger}</upload>;
  299. return (
  300. <div>
  301. { this.listType === 'picture-card' ? uploadList : ''}
  302. {
  303. this.$slots.trigger
  304. ? [uploadComponent, this.$slots.default]
  305. : uploadComponent
  306. }
  307. {this.$slots.tip}
  308. { this.listType !== 'picture-card' ? uploadList : ''}
  309. </div>
  310. );
  311. }
  312. };
  313. </script>