You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Breakpoint.vue 7.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <template>
  2. <div id="page">
  3. <header>
  4. <h1 class="logo"><a href="http://www.helloweba.net" title="返回helloweba首页">helloweba</a></h1>
  5. </header>
  6. <div class="main">
  7. <h2><a href="http://www.helloweba.net/javascript/637.html">文件上传之暂停和断点续传和跨浏览器续传</a></h2>
  8. <uploader
  9. ref="uploader"
  10. :options="options"
  11. :file-status-text="fileStatusText"
  12. :autoStart="false"
  13. @file-added="onFileAdded"
  14. @file-progress="onFileProgress"
  15. @file-success="onFileSuccess"
  16. @file-error="onFileError"
  17. class="uploader">
  18. <uploader-unsupport></uploader-unsupport>
  19. <uploader-drop>
  20. <uploader-btn class="upfile"><i class="iconfont icon-upload"></i> 上传文件</uploader-btn>
  21. <uploader-btn class="updir" :directory="true"><i class="iconfont icon-dir"></i> 上传文件夹</uploader-btn>
  22. </uploader-drop>
  23. <uploader-list></uploader-list>
  24. </uploader>
  25. </div>
  26. <footer>
  27. <p>Powered by helloweba.net 允许转载、修改和使用本站的DEMO,但请注明出处:<a href="http://www.helloweba.net">www.helloweba.net</a></p>
  28. <p class="hidden"></p>
  29. </footer>
  30. </div>
  31. </template>
  32. <script>
  33. import axios from 'axios';
  34. import SparkMD5 from 'spark-md5';
  35. export default {
  36. data () {
  37. return {
  38. options: {
  39. target: 'http://localhost:9999/up.php',
  40. chunkSize: 2097152, //2MB
  41. simultaneousUploads: 1, //并发上传数
  42. headers: {
  43. 'X-token': 'abcd123'
  44. },
  45. maxChunkRetries: 2, //最大自动失败重试上传次数
  46. parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) { //格式化时间
  47. return parsedTimeRemaining
  48. .replace(/\syears?/, '年')
  49. .replace(/\days?/, '天')
  50. .replace(/\shours?/, '小时')
  51. .replace(/\sminutes?/, '分钟')
  52. .replace(/\sseconds?/, '秒')
  53. },
  54. testChunks: true, //开启服务端分片校验
  55. // 服务器分片校验函数
  56. checkChunkUploadedByResponse: (chunk, message) => {
  57. let obj = JSON.parse(message);
  58. if (obj.isExist) {
  59. this.statusTextMap.success = '秒传文件';
  60. return true;
  61. }
  62. return (obj.uploaded || []).indexOf(chunk.offset + 1) >= 0
  63. },
  64. },
  65. statusTextMap: {
  66. success: '上传成功',
  67. error: '上传出错了',
  68. uploading: '上传中...',
  69. paused: '暂停',
  70. waiting: '等待中...',
  71. cmd5: '计算md5...'
  72. },
  73. fileStatusText: (status, response) => {
  74. return this.statusTextMap[status];
  75. },
  76. }
  77. },
  78. created() {
  79. //
  80. },
  81. methods: {
  82. onFileAdded(file) {
  83. // 计算MD5
  84. this.computeMD5(file);
  85. },
  86. //计算MD5
  87. computeMD5(file) {
  88. let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
  89. chunkSize = 2097152,
  90. chunks = Math.ceil(file.size / chunkSize),
  91. currentChunk = 0,
  92. spark = new SparkMD5.ArrayBuffer(),
  93. fileReader = new FileReader();
  94. let time = new Date().getTime();
  95. file.cmd5 = true;
  96. fileReader.onload = (e) => {
  97. spark.append(e.target.result); // Append array buffer
  98. currentChunk++;
  99. if (currentChunk < chunks) {
  100. //console.log(`第${currentChunk}分片解析完成, 开始第${currentChunk +1} / ${chunks}分片解析`);
  101. let percent = Math.floor(currentChunk / chunks * 100);
  102. file.cmd5progress = percent;
  103. loadNext();
  104. } else {
  105. console.log('finished loading');
  106. let md5 = spark.end();
  107. console.log(`MD5计算完成:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);
  108. spark.destroy(); //释放缓存
  109. file.uniqueIdentifier = md5; //将文件md5赋值给文件唯一标识
  110. file.cmd5 = false; //取消计算md5状态
  111. file.resume(); //开始上传
  112. }
  113. };
  114. fileReader.onerror = () => {
  115. console.warn('oops, something went wrong.');
  116. file.cancel();
  117. };
  118. let loadNext = () => {
  119. let start = currentChunk * chunkSize,
  120. end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
  121. fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
  122. };
  123. loadNext();
  124. },
  125. // 文件进度的回调
  126. onFileProgress(rootFile, file, chunk) {
  127. console.log(`上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`)
  128. },
  129. onFileSuccess(rootFile, file, response, chunk) {
  130. let resp = JSON.parse(response);
  131. //合并分片
  132. if (resp.code === 0 && resp.merge === true) {
  133. axios.post('http://localhost:9999/up.php?action=merge', {
  134. filename: file.name,
  135. identifier: file.uniqueIdentifier,
  136. totalSize: file.size,
  137. totalChunks: chunk.offset + 1
  138. }).then(function(res){
  139. if (res.code === 0) {
  140. console.log('上传成功')
  141. } else {
  142. console.log(res.message);
  143. }
  144. })
  145. .catch(function(error){
  146. console.log(error);
  147. });
  148. }
  149. },
  150. onFileError(rootFile, file, response, chunk) {
  151. console.log('Error:', response)
  152. },
  153. }
  154. }
  155. </script>
  156. <style scoped lang="less">
  157. .main{
  158. max-width: 1000px;
  159. margin: 10px auto;
  160. background: #fff;
  161. padding: 10px;
  162. h2{
  163. padding: 30px 0;
  164. text-align: center;
  165. font-size: 20px;
  166. }
  167. }
  168. .uploader {
  169. width: 880px;
  170. padding: 15px;
  171. margin: 20px auto 0;
  172. font-size: 14px;
  173. box-shadow: 0 0 10px rgba(0, 0, 0, .4);
  174. .uploader-btn {
  175. margin-right: 4px;
  176. color: #fff;
  177. padding: 6px 16px;
  178. }
  179. .upfile{
  180. border: 1px solid #409eff;
  181. background: #409eff;
  182. }
  183. .updir{
  184. border: 1px solid #67c23a;
  185. background: #67c23a;
  186. }
  187. .uploader-list {
  188. max-height: 440px;
  189. overflow: auto;
  190. overflow-x: hidden;
  191. overflow-y: auto;
  192. height: 356px;
  193. /deep/.iconfont {
  194. font-size: 18px;
  195. color: #409eff;
  196. }
  197. }
  198. }
  199. //手机等小屏幕手持设备。当设备宽度 在 320px和768px之间时,执行当前的css
  200. @media only screen and (min-width: 320px) and (max-width: 768px) {
  201. .uploader {
  202. width: 98%;
  203. padding: 0;
  204. box-shadow: none;
  205. }
  206. }
  207. </style>