index.vue 8.2 KB

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