index.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <template>
  2. <div :id="id" :ref="id" :action="uploadUrl" class="dropzone">
  3. <input type="file" name="file">
  4. </div>
  5. </template>
  6. <script>
  7. import Dropzone from 'dropzone'
  8. import 'dropzone/dist/dropzone.css'
  9. // import { getToken } from 'api/qiniu';
  10. Dropzone.autoDiscover = false
  11. export default {
  12. props: {
  13. id: {
  14. type: String,
  15. required: true
  16. },
  17. url: {
  18. type: String,
  19. required: false
  20. },
  21. clickable: {
  22. type: Boolean,
  23. default: true
  24. },
  25. defaultMsg: {
  26. type: String,
  27. default: '上传图片'
  28. },
  29. acceptedFiles: {
  30. type: String,
  31. default: 'image/*'
  32. },
  33. thumbnailHeight: {
  34. type: Number,
  35. default: 200
  36. },
  37. thumbnailWidth: {
  38. type: Number,
  39. default: 200
  40. },
  41. showRemoveLink: {
  42. type: Boolean,
  43. default: true
  44. },
  45. maxFilesize: {
  46. type: Number,
  47. default: 100
  48. },
  49. maxFiles: {
  50. type: Number,
  51. default: 100
  52. },
  53. autoProcessQueue: {
  54. type: Boolean,
  55. default: true
  56. },
  57. useCustomDropzoneOptions: {
  58. type: Boolean,
  59. default: false
  60. },
  61. defaultImg: {
  62. default: '',
  63. type: [String, Array]
  64. },
  65. couldPaste: {
  66. type: Boolean,
  67. default: false
  68. }
  69. },
  70. created() {
  71. this.uploadUrl = this.url ? this.url : `${process.env.VUE_APP_BASE_API}/api/files/upload`
  72. },
  73. data() {
  74. return {
  75. dropzone: '',
  76. uploadUrl: '',
  77. initOnce: true,
  78. }
  79. },
  80. watch: {
  81. defaultImg(val) {
  82. if (val.length === 0) {
  83. this.initOnce = false
  84. return
  85. }
  86. if (!this.initOnce) return
  87. this.initImages(val)
  88. this.initOnce = false
  89. }
  90. },
  91. mounted() {
  92. const element = document.getElementById(this.id)
  93. const vm = this
  94. this.dropzone = new Dropzone(element, {
  95. headers: { Authorization: this.$store.getters.token },
  96. clickable: this.clickable,
  97. thumbnailWidth: this.thumbnailWidth,
  98. thumbnailHeight: this.thumbnailHeight,
  99. maxFiles: this.maxFiles,
  100. maxFilesize: this.maxFilesize,
  101. dictRemoveFile: 'Remove',
  102. addRemoveLinks: this.showRemoveLink,
  103. acceptedFiles: this.acceptedFiles,
  104. autoProcessQueue: this.autoProcessQueue,
  105. dictDefaultMessage: '<i style="margin-top: 3em;display: inline-block" class="material-icons">' + this.defaultMsg + '</i><br>Drop files here to upload',
  106. dictMaxFilesExceeded: '只能一个图',
  107. previewTemplate: '<div class="dz-preview dz-file-preview"> <div class="dz-image" style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" ><img style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" data-dz-thumbnail /></div> <div class="dz-details"> <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div> <div class="dz-error-message"><span data-dz-errormessage></span></div> <div class="dz-success-mark"> <i class="material-icons">done</i> </div> <div class="dz-error-mark"><i class="material-icons">error</i></div></div>',
  108. init() {
  109. const val = vm.defaultImg
  110. if (!val) return
  111. if (Array.isArray(val)) {
  112. if (val.length === 0) return
  113. val.map((v, i) => {
  114. const mockFile = { name: 'name' + i, size: 12345, url: v }
  115. this.options.addedfile.call(this, mockFile)
  116. this.options.thumbnail.call(this, mockFile, v)
  117. mockFile.previewElement.classList.add('dz-success')
  118. mockFile.previewElement.classList.add('dz-complete')
  119. vm.initOnce = false
  120. return true
  121. })
  122. } else {
  123. const mockFile = { name: 'name', size: 12345, url: val }
  124. this.options.addedfile.call(this, mockFile)
  125. this.options.thumbnail.call(this, mockFile, val)
  126. mockFile.previewElement.classList.add('dz-success')
  127. mockFile.previewElement.classList.add('dz-complete')
  128. vm.initOnce = false
  129. }
  130. },
  131. accept: (file, done) => {
  132. /* 七牛*/
  133. // const token = this.$store.getters.token;
  134. // getToken(token).then(response => {
  135. // file.token = response.data.qiniu_token;
  136. // file.key = response.data.qiniu_key;
  137. // file.url = response.data.qiniu_url;
  138. // done();
  139. // })
  140. done()
  141. },
  142. sending: (file, xhr, formData) => {
  143. // formData.append('token', file.token);
  144. // formData.append('key', file.key);
  145. vm.initOnce = false
  146. }
  147. })
  148. if (this.couldPaste) {
  149. document.addEventListener('paste', this.pasteImg)
  150. }
  151. this.dropzone.on('success', (file, response) => {
  152. file.fileUrl = response.url
  153. file.dropzoneId = vm.dropzone.element.id
  154. vm.$emit('dropzone-success', file, vm.dropzone.element)
  155. })
  156. this.dropzone.on('addedfile', file => {
  157. vm.$emit('dropzone-fileAdded', file)
  158. })
  159. this.dropzone.on('removedfile', file => {
  160. vm.$emit('dropzone-removedFile', file, )
  161. })
  162. this.dropzone.on('error', (file, error, xhr) => {
  163. vm.$emit('dropzone-error', file, error, xhr)
  164. })
  165. this.dropzone.on('successmultiple', (file, error, xhr) => {
  166. vm.$emit('dropzone-successmultiple', file, error, xhr)
  167. })
  168. },
  169. destroyed() {
  170. document.removeEventListener('paste', this.pasteImg)
  171. this.dropzone.destroy()
  172. },
  173. methods: {
  174. removeAllFiles() {
  175. this.dropzone.removeAllFiles(true)
  176. },
  177. processQueue() {
  178. this.dropzone.processQueue()
  179. },
  180. pasteImg(event) {
  181. const items = (event.clipboardData || event.originalEvent.clipboardData).items
  182. if (items[0].kind === 'file') {
  183. this.dropzone.addFile(items[0].getAsFile())
  184. }
  185. },
  186. initImages(val) {
  187. if (!val) return
  188. if (Array.isArray(val)) {
  189. val.map((v, i) => {
  190. const fileUrl = `${process.env.VUE_APP_BASE_API}/api/files/view-file?path=${v}`
  191. const mockFile = { url: fileUrl }
  192. this.dropzone.options.addedfile.call(this.dropzone, mockFile)
  193. this.dropzone.options.thumbnail.call(this.dropzone, mockFile, fileUrl)
  194. mockFile.previewElement.classList.add('dz-success')
  195. mockFile.previewElement.classList.add('dz-complete')
  196. return true
  197. })
  198. } else {
  199. const fileUrl = `${process.env.VUE_APP_BASE_API}/api/files/view-file?path=${val}`
  200. const mockFile = { url: fileUrl }
  201. this.dropzone.options.addedfile.call(this.dropzone, mockFile)
  202. this.dropzone.options.thumbnail.call(this.dropzone, mockFile, fileUrl)
  203. mockFile.previewElement.classList.add('dz-success')
  204. mockFile.previewElement.classList.add('dz-complete')
  205. }
  206. }
  207. }
  208. }
  209. </script>
  210. <style scoped>
  211. .dropzone {
  212. border: 2px solid #E5E5E5;
  213. font-family: 'Roboto', sans-serif;
  214. color: #777;
  215. transition: background-color .2s linear;
  216. padding: 5px;
  217. }
  218. .dropzone:hover {
  219. background-color: #F6F6F6;
  220. }
  221. i {
  222. color: #CCC;
  223. }
  224. .dropzone .dz-image img {
  225. width: 100%;
  226. height: 100%;
  227. }
  228. .dropzone input[name='file'] {
  229. display: none;
  230. }
  231. .dropzone .dz-preview .dz-image {
  232. border-radius: 0px;
  233. }
  234. .dropzone .dz-preview:hover .dz-image img {
  235. transform: none;
  236. filter: none;
  237. width: 100%;
  238. height: 100%;
  239. }
  240. .dropzone .dz-preview .dz-details {
  241. bottom: 0px;
  242. top: 0px;
  243. color: white;
  244. background-color: rgba(33, 150, 243, 0.8);
  245. transition: opacity .2s linear;
  246. text-align: left;
  247. }
  248. .dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span {
  249. background-color: transparent;
  250. }
  251. .dropzone .dz-preview .dz-details .dz-filename:not(:hover) span {
  252. border: none;
  253. }
  254. .dropzone .dz-preview .dz-details .dz-filename:hover span {
  255. background-color: transparent;
  256. border: none;
  257. }
  258. .dropzone .dz-preview .dz-remove {
  259. position: absolute;
  260. z-index: 30;
  261. color: white;
  262. margin-left: 15px;
  263. padding: 10px;
  264. top: inherit;
  265. bottom: 15px;
  266. border: 2px white solid;
  267. text-decoration: none;
  268. text-transform: uppercase;
  269. font-size: 0.8rem;
  270. font-weight: 800;
  271. letter-spacing: 1.1px;
  272. opacity: 0;
  273. }
  274. .dropzone .dz-preview:hover .dz-remove {
  275. opacity: 1;
  276. }
  277. .dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark {
  278. margin-left: -40px;
  279. margin-top: -50px;
  280. }
  281. .dropzone .dz-preview .dz-success-mark i, .dropzone .dz-preview .dz-error-mark i {
  282. color: white;
  283. font-size: 5rem;
  284. }
  285. </style>