断点续传是指在文件上传过程中,如果因为网络或其他原因导致上传中断,可以在中断的位置继续上传,而不需要重新上传整个文件。下面是使用 Vue + Element + Axios + qs 实现断点续传的步骤:
1. 安装 Element 和 Axios
```
npm install element-ui axios --save
```
2. 创建上传组件
在 Vue 的组件中,使用 Element 的上传组件和 Axios 进行文件上传。首先,我们需要在模板中添加一个上传组件:
```html
<el-upload
class="upload-demo"
ref="upload"
:action="uploadUrl"
:data="uploadData"
:file-list="fileList"
:auto-upload="false"
:on-success="handleSuccess"
:on-error="handleError"
>
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
<el-button size="small" type="success" @click="submitUpload">上传到服务器</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
```
其中,`uploadUrl` 是上传接口的地址,`uploadData` 是上传接口的参数,`fileList` 是上传的文件列表,`handleSuccess` 和 `handleError` 是上传成功和失败的回调函数。
3. 实现上传方法
在 Vue 的方法中,实现文件上传的方法:
```javascript
submitUpload() {
this.$refs.upload.submit();
},
handleSuccess(response, file, fileList) {
// 处理上传成功的逻辑
},
handleError(err, file, fileList) {
// 处理上传失败的逻辑
}
```
在 `submitUpload` 方法中,调用上传组件的 `submit` 方法进行文件上传。在 `handleSuccess` 方法中,处理上传成功的逻辑,包括显示上传成功的提示信息、更新文件列表等。在 `handleError` 方法中,处理上传失败的逻辑,包括显示上传失败的提示信息、更新文件列表等。
4. 实现断点续传
要实现断点续传,需要在上传组件中添加 `before-upload` 和 `on-progress` 事件,分别处理上传前和上传中的逻辑。在 `before-upload` 事件中,检查文件是否已经上传过,如果上传过,就设置上传的起点为上次上传结束的位置,否则上传整个文件。在 `on-progress` 事件中,更新上传进度。
```html
<el-upload
class="upload-demo"
ref="upload"
:action="uploadUrl"
:data="uploadData"
:file-list="fileList"
:auto-upload="false"
:before-upload="beforeUpload"
:on-progress="onProgress"
:on-success="handleSuccess"
:on-error="handleError"
>
```
```javascript
beforeUpload(file) {
// 判断文件是否已经上传过
if (localStorage.getItem(file.name)) {
// 设置上传的起点为上次上传结束的位置
this.uploadData.start = JSON.parse(localStorage.getItem(file.name)).end;
} else {
// 上传整个文件
this.uploadData.start = 0;
}
},
onProgress(event, file, fileList) {
// 更新上传进度
const progress = Math.round((event.loaded / event.total) * 100);
this.$set(file, "progress", progress);
}
```
在 `before-upload` 事件中,使用 `localStorage` 存储文件上传结束位置,以便下次继续上传。在 `on-progress` 事件中,计算上传进度并更新文件列表中对应文件的进度。
5. 实现暂停上传和恢复上传
要实现暂停上传和恢复上传,可以在上传组件中添加两个按钮,分别用于暂停和恢复上传。在暂停上传时,保存上传进度并中止上传。在恢复上传时,从上次保存的上传进度开始上传。
```html
<el-upload
...
>
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
<el-button size="small" type="success" @click="submitUpload">上传到服务器</el-button>
<el-button size="small" type="warning" v-show="!isUploading" @click="resumeUpload">恢复上传</el-button>
<el-button size="small" type="danger" v-show="isUploading" @click="pauseUpload">暂停上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
```
```javascript
data() {
return {
isUploading: false,
uploadProgress: 0
};
},
methods: {
submitUpload() {
this.$refs.upload.submit();
this.isUploading = true;
},
pauseUpload() {
this.$refs.upload.abort();
this.isUploading = false;
},
resumeUpload() {
this.$refs.upload.submit();
this.isUploading = true;
},
beforeUpload(file) {
...
},
onProgress(event, file, fileList) {
...
this.uploadProgress = progress;
file.progress = progress;
}
}
```
在 Vue 的数据中,添加 `isUploading` 和 `uploadProgress` 两个变量,分别表示上传状态和上传进度。在方法中,实现暂停上传和恢复上传的逻辑,使用 `isUploading` 变量控制按钮的显示。在 `before-upload` 和 `on-progress` 事件中,更新上传状态和上传进度。
6. 完整代码
```html
<template>
<div>
<el-upload
class="upload-demo"
ref="upload"
:action="uploadUrl"
:data="uploadData"
:file-list="fileList"
:auto-upload="false"
:before-upload="beforeUpload"
:on-progress="onProgress"
:on-success="handleSuccess"
:on-error="handleError"
>
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
<el-button size="small" type="success" @click="submitUpload">上传到服务器</el-button>
<el-button size="small" type="warning" v-show="!isUploading" @click="resumeUpload">恢复上传</el-button>
<el-button size="small" type="danger" v-show="isUploading" @click="pauseUpload">暂停上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
</div>
</template>
<script>
import { Upload, Button } from "element-ui";
import axios from "axios";
import qs from "qs";
export default {
name: "UploadComponent",
components: {
"el-upload": Upload,
"el-button": Button
},
data() {
return {
isUploading: false,
uploadProgress: 0,
uploadUrl: "/upload",
uploadData: {
start: 0
},
fileList: []
};
},
methods: {
submitUpload() {
this.$refs.upload.submit();
this.isUploading = true;
},
pauseUpload() {
this.$refs.upload.abort();
this.isUploading = false;
},
resumeUpload() {
this.$refs.upload.submit();
this.isUploading = true;
},
beforeUpload(file) {
if (localStorage.getItem(file.name)) {
this.uploadData.start = JSON.parse(localStorage.getItem(file.name)).end;
} else {
this.uploadData.start = 0;
}
},
onProgress(event, file, fileList) {
const progress = Math.round((event.loaded / event.total) * 100);
this.uploadProgress = progress;
file.progress = progress;
localStorage.setItem(
file.name,
JSON.stringify({
end: this.uploadData.start + event.loaded
})
);
},
handleSuccess(response, file, fileList) {
this.fileList = fileList;
this.isUploading = false;
localStorage.removeItem(file.name);
this.$message({
message: "上传成功",
type: "success"
});
},
handleError(err, file, fileList) {
this.fileList = fileList;
this.isUploading = false;
this.$message.error("上传失败");
}
}
};
</script>
```