|
- <template>
- <div id="page">
- <header>
- <h1 class="logo"><a href="http://www.helloweba.net" title="返回helloweba首页">helloweba</a></h1>
- </header>
-
- <div class="main">
- <h2><a href="http://www.helloweba.net/javascript/637.html">文件上传之暂停和断点续传和跨浏览器续传</a></h2>
- <uploader
- ref="uploader"
- :options="options"
- :file-status-text="fileStatusText"
- :autoStart="false"
- @file-added="onFileAdded"
- @file-progress="onFileProgress"
- @file-success="onFileSuccess"
- @file-error="onFileError"
- class="uploader">
- <uploader-unsupport></uploader-unsupport>
- <uploader-drop>
- <uploader-btn class="upfile"><i class="iconfont icon-upload"></i> 上传文件</uploader-btn>
- <uploader-btn class="updir" :directory="true"><i class="iconfont icon-dir"></i> 上传文件夹</uploader-btn>
- </uploader-drop>
- <uploader-list></uploader-list>
- </uploader>
- </div>
-
- <footer>
- <p>Powered by helloweba.net 允许转载、修改和使用本站的DEMO,但请注明出处:<a href="http://www.helloweba.net">www.helloweba.net</a></p>
- <p class="hidden"></p>
- </footer>
- </div>
- </template>
-
- <script>
- import axios from 'axios';
- import SparkMD5 from 'spark-md5';
-
- export default {
- data () {
- return {
- options: {
- target: 'http://localhost:9999/up.php',
- chunkSize: 2097152, //2MB
- simultaneousUploads: 1, //并发上传数
- headers: {
- 'X-token': 'abcd123'
- },
- maxChunkRetries: 2, //最大自动失败重试上传次数
- parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) { //格式化时间
- return parsedTimeRemaining
- .replace(/\syears?/, '年')
- .replace(/\days?/, '天')
- .replace(/\shours?/, '小时')
- .replace(/\sminutes?/, '分钟')
- .replace(/\sseconds?/, '秒')
- },
- testChunks: true, //开启服务端分片校验
- // 服务器分片校验函数
- checkChunkUploadedByResponse: (chunk, message) => {
- let obj = JSON.parse(message);
- if (obj.isExist) {
- this.statusTextMap.success = '秒传文件';
- return true;
- }
-
- return (obj.uploaded || []).indexOf(chunk.offset + 1) >= 0
- },
- },
-
- statusTextMap: {
- success: '上传成功',
- error: '上传出错了',
- uploading: '上传中...',
- paused: '暂停',
- waiting: '等待中...',
- cmd5: '计算md5...'
- },
-
- fileStatusText: (status, response) => {
- return this.statusTextMap[status];
- },
- }
- },
- created() {
- //
- },
- methods: {
- onFileAdded(file) {
- // 计算MD5
- this.computeMD5(file);
- },
-
- //计算MD5
- computeMD5(file) {
- let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
- chunkSize = 2097152,
- chunks = Math.ceil(file.size / chunkSize),
- currentChunk = 0,
- spark = new SparkMD5.ArrayBuffer(),
- fileReader = new FileReader();
-
- let time = new Date().getTime();
-
- file.cmd5 = true;
-
- fileReader.onload = (e) => {
- spark.append(e.target.result); // Append array buffer
- currentChunk++;
-
- if (currentChunk < chunks) {
- //console.log(`第${currentChunk}分片解析完成, 开始第${currentChunk +1} / ${chunks}分片解析`);
- let percent = Math.floor(currentChunk / chunks * 100);
- file.cmd5progress = percent;
- loadNext();
- } else {
- console.log('finished loading');
- let md5 = spark.end();
- console.log(`MD5计算完成:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);
- spark.destroy(); //释放缓存
- file.uniqueIdentifier = md5; //将文件md5赋值给文件唯一标识
- file.cmd5 = false; //取消计算md5状态
- file.resume(); //开始上传
- }
- };
-
- fileReader.onerror = () => {
- console.warn('oops, something went wrong.');
- file.cancel();
- };
-
- let loadNext = () => {
- let start = currentChunk * chunkSize,
- end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
-
- fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
- };
-
- loadNext();
- },
- // 文件进度的回调
- onFileProgress(rootFile, file, chunk) {
- console.log(`上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`)
- },
- onFileSuccess(rootFile, file, response, chunk) {
- let resp = JSON.parse(response);
- //合并分片
- if (resp.code === 0 && resp.merge === true) {
- axios.post('http://localhost:9999/up.php?action=merge', {
- filename: file.name,
- identifier: file.uniqueIdentifier,
- totalSize: file.size,
- totalChunks: chunk.offset + 1
- }).then(function(res){
- if (res.code === 0) {
- console.log('上传成功')
- } else {
- console.log(res.message);
- }
- })
- .catch(function(error){
- console.log(error);
- });
- }
- },
-
- onFileError(rootFile, file, response, chunk) {
- console.log('Error:', response)
- },
- }
- }
- </script>
-
- <style scoped lang="less">
- .main{
- max-width: 1000px;
- margin: 10px auto;
-
- background: #fff;
- padding: 10px;
- h2{
- padding: 30px 0;
- text-align: center;
- font-size: 20px;
- }
- }
-
- .uploader {
- width: 880px;
- padding: 15px;
- margin: 20px auto 0;
- font-size: 14px;
- box-shadow: 0 0 10px rgba(0, 0, 0, .4);
- .uploader-btn {
- margin-right: 4px;
- color: #fff;
- padding: 6px 16px;
- }
- .upfile{
- border: 1px solid #409eff;
- background: #409eff;
- }
- .updir{
- border: 1px solid #67c23a;
- background: #67c23a;
- }
- .uploader-list {
- max-height: 440px;
- overflow: auto;
- overflow-x: hidden;
- overflow-y: auto;
-
- height: 356px;
- /deep/.iconfont {
- font-size: 18px;
- color: #409eff;
- }
- }
-
- }
-
- //手机等小屏幕手持设备。当设备宽度 在 320px和768px之间时,执行当前的css
- @media only screen and (min-width: 320px) and (max-width: 768px) {
- .uploader {
- width: 98%;
- padding: 0;
- box-shadow: none;
- }
- }
- </style>
|