前言
因為項目需要上傳大文件tif圖,考慮使用分片上傳。
1、安裝
npm install vue-simple-uploader --save
2、main.js中初始化
import uploader from 'vue-simple-uploader'
Vue.use(uploader)
注:直接在vue文件中引用,居然加載不出來,不清楚原因
3、定義在template中的模板
點擊查看代碼
<uploader
ref="uploaderRef"
:autoStart="false"
:options="options"
class="uploader-example"
@file-success="onFileSuccess"
@file-added="filesAdded"
@file-error="onFileError"
:file-status-text="fileStatusText"
>
<uploader-unsupport></uploader-unsupport>
<uploader-drop>
<p>將文件拖放到此處以上傳或</p>
<!-- <uploader-btn>select files</uploader-btn> -->
<uploader-btn :attrs="attrs" :single="true">選擇遙感圖片</uploader-btn>
<!-- <uploader-btn :directory="true">select folder</uploader-btn> -->
</uploader-drop>
<uploader-list></uploader-list>
</uploader>
4、定義在script中的數據
點擊查看代碼
import SparkMD5 from 'spark-md5'
export default {
props: {
name: {
type: String,
default: 'file'
},
chunkSize: {
type: Number,
default: 0
},
action: {
type: String,
default: 'http://xxx.xxx.xx'
}
},
data () {
return {
options: {
target: this.action, // 目標上傳 URL
chunkSize: this.chunkSize, // 分塊大小
fileParameterName: this.name, // 上傳文件時文件的參數名,默認file
// maxChunkRetries: 3, // 最大自動失敗重試上傳次數
testChunks: false, // 是否開啟服務器分片校驗
// // 服務器分片校驗函數,秒傳及斷點續傳基礎
checkChunkUploadedByResponse: function (chunk, message) {
const objMessage = JSON.parse(message)
if (objMessage.skipUpload) {
return true
}
return (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0
},
processParams (params) {
console.log(params)
// 每一次分片傳給后台的參數,params是該方法返回的形參,包含分片信息
return {
// 返回一個對象,會添加到每一個分片的請求參數里面
filename: params.filename,
identifier: params.identifier,
totalChunks: params.totalChunks,
chunkNumber: params.chunkNumber,
totalSize: params.totalSize
}
},
headers: {
// 在header中添加的驗證,請根據實際業務來
token: this.$store.getters['user/token']
}
// 自定義參數,隨每一個切片發送
// query:{
// //列如,參數id
// id:''
// },
},
statusTextMap: {
success: '上傳成功',
error: '上傳失敗',
uploading: '上傳中',
paused: '暫停中',
waiting: '等待中'
},
attrs: {
// 接受的文件類型,形如['.png', '.jpg', '.jpeg', '.gif', '.bmp'...]
accept: ['.tif', '.tiff']
},
// 將不同的狀態對應文字
fileStatusText: (status, response) => {
return this.statusTextMap[status]
}
}
},
methods: {
onFileSuccess (rootFile, file, response, chunk) {
console.log(response)
const res = JSON.parse(response)
// 切片上傳成功,調用合並
if (res.code === 200) {
this.$emit('needMerger', file.uniqueIdentifier)
}
},
onFileError (rootFile, file, response, chunk) {
// 文件上傳失敗的回調
console.log(rootFile, file, response, chunk)
this.$emit('onFileError')
},
computeMD5 (file) {
const loading = this.$loading({
lock: true,
text: '正在計算文件大小',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
const fileReader = new FileReader()
const time = new Date().getTime()
const blobSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice
let currentChunk = 0
const chunkSize = 10 * 1024 * 1000
const chunks = Math.ceil(file.size / chunkSize)
const spark = new SparkMD5.ArrayBuffer()
file.pause()
loadNext()
fileReader.onload = e => {
spark.append(e.target.result)
if (currentChunk < chunks) {
currentChunk++
loadNext()
this.$nextTick(() => {
console.log(
'校驗MD5 ' + ((currentChunk / chunks) * 100).toFixed(0) + '%'
)
})
} else {
const md5 = spark.end()
loading.close()
this.computeMD5Success(md5, file)
console.log(
`MD5計算完畢:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
file.size
} 用時:${new Date().getTime() - time} ms`
)
}
}
fileReader.onerror = function () {
this.error(`文件${file.name}讀取出錯,請檢查該文件`)
loading.close()
file.cancel()
}
function loadNext () {
const start = currentChunk * chunkSize
const end =
start + chunkSize >= file.size ? file.size : start + chunkSize
fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end))
}
},
computeMD5Success (md5, file) {
file.uniqueIdentifier = md5 // 把md5值作為文件的識別碼
},
filesAdded (file, event) {
if (this.$refs.uploaderRef.files.length === 1) {
// 只上傳一張,將上一張覆蓋
this.$refs.uploaderRef.files[0].cancel()
}
if (file.size / 1024 / 1024 / 1024 > 2) {
// 文件不能大於2G
this.form.videoUrl = ''
this.$message.warning('文件大小不能超過2G')
setTimeout(() => {
this.$refs.uploaderRef.uploader.removeFile(file)
}, 0)
return false
}
this.computeMD5(file)
}
}
}
5、在父組件中調用上傳方法
點擊查看代碼
<hr-upload
name="remote"
:chunkSize="10 * 1024 * 1024"
:action="action"
ref="upload"
@onFileError="onFileError"
@needMerger="needMerger"
></hr-upload>
this.$refs.upload.$refs.uploaderRef.files[0].resume()