Vue 큰 파일 업로드 와 정지점 전송 실현
파일 흐름 기반(form-data)
element-ui 프레임 워 크 의 업로드 구성 요 소 는 기본적으로 파일 흐름 을 기반 으로 합 니 다.
데이터 형식:form-data;
클 라 이언 트 가 파일 을 base 64 로 변환 합 니 다.
fileRead.readAsDataURL(file)을 통 해 base 64 문자열 로 변환 한 후 encodeURIComponent 로 컴 파일 하여 보 내야 합 니 다.보 낸 데 이 터 는 qs.stringify 처 리 를 통 해"Content-Type"을 추가 하 십시오."application/x-ww-form-urlencoded"
파일 업로드
우선 element-ui 를 통 해 페이지 를 만 듭 니 다.업로드 의 실현 을 사용자 정의 해 야 하기 때문에 el-uproad 구성 요소 의 auto-uproad 는 false 로 설정 해 야 합 니 다.action 은 필수 매개 변수 입 니 다.값 을 채 우지 않 아 도 됩 니 다.
<template>
<div id="app">
<!-- -->
<el-upload action drag :auto-upload="false" :show-file-list="false" :on-change="handleChange">
<i class="el-icon-upload"></i>
<div class="el-upload__text"> , <em> </em></div>
<div class="el-upload__tip" slot="tip"> 200M </div>
</el-upload>
<!-- -->
<div class="progress-box">
<span> :{{ percent.toFixed() }}%</span>
<el-button type="primary" size="mini" @click="handleClickBtn">{{ upload | btnTextFilter}}</el-button>
</div>
<!-- -->
<div v-if="videoUrl">
<video :src="videoUrl" controls />
</div>
</div>
</template>
파일 대상 가 져 오기 및 Array Buffer 대상 으로 전환Array Buffer 로 전환 한 것 은 뒤에 SparkMD 5 라 이브 러 리 로 hash 값 을 생 성하 고 파일 이름 을 짓 기 때 문 입 니 다.
async handleChange(file) {
const fileObj = file.raw
try{
const buffer = await this.fileToBuffer(fileObj)
console.log(buffer)
}catch(e){
console.log(e)
}
}
다음 그림 과 같이 buffer 결 과 를 인쇄 합 니 다.메모:before-uproad 함수 와 on-change 함수 의 매개 변 수 는 모두 file 이 있 습 니 다.그러나 on-change 의 file 은 File 대상 이 아 닙 니 다.File 대상 을 얻 으 려 면 file.raw 를 통 해 가 져 와 야 합 니 다.FileReader 클래스 를 사용 하여 File 대상 을 Array Buffer 대상 으로 전환 합 니 다.비동기 프로 세 스 이기 때문에 Promise 로 패키지 합 니 다.
// File ArrayBuffer
fileToBuffer(file) {
return new Promise((resolve, reject) => {
const fr = new FileReader()
fr.onload = e => {
resolve(e.target.result)
}
fr.readAsArrayBuffer(file)
fr.onerror = () => {
reject(new Error(' '))
}
})
}
절편 만 들 기고정 크기 나 고정 수량 을 통 해 하나의 파일 을 여러 부분 으로 나 눌 수 있 습 니 다.js 가 사용 하 는 IEEE 754 바 이 너 리 부동 소수점 산술 기준 으로 인해 발생 할 수 있 는 오 차 를 피하 기 위해 저 는 고정 크기 의 방식 으로 파일 을 자 르 고 각 절편 의 크기 를 2M,즉 2M=21024 KB=21024*1024 B=2097152 B 로 설정 하기 로 했 습 니 다.파일 을 자 르 는 데 사용 되 는 것 은 Blob.slice()입 니 다.
// (2M) ,
const chunkSize = 2097152,
chunkList = [], //
chunkListLength = Math.ceil(fileObj.size / chunkSize), //
suffix = /\.([0-9A-z]+)$/.exec(fileObj.name)[1] //
// hash
const spark = new SparkMD5.ArrayBuffer()
spark.append(buffer)
const hash = spark.end()
// , (chunk) (fileName)
let curChunk = 0 //
for (let i = 0; i < chunkListLength; i++) {
const item = {
chunk: fileObj.slice(curChunk, curChunk + chunkSize),
fileName: `${hash}_${i}.${suffix}` // hash_1.jpg
}
curChunk += chunkSize
chunkList.push(item)
}
console.log(chunkList)
파일 을 선택 하면 다음 그림 과 같은 결 과 를 출력 합 니 다.송신 요청
보 내기 요청 은 병렬 또는 직렬 로 보 낼 수 있 습 니 다.직렬 로 보 내 는 것 을 선택 하 십시오.절편 마다 새로운 요청 이 있 습 니 다.정지점 전송 을 실현 하기 위해 함수 fn 에 봉인 을 요청 합 니 다.요청 집합 을 배열 requestList 로 저장 한 다음 send 함 수 를 봉인 하여 전송 을 요청 합 니 다.그러면 일시 정지 키 를 누 르 면 업로드 가 편리 합 니 다.코드 는 다음 과 같 습 니 다.
sendRequest() {
const requestList = [] //
this.chunkList.forEach(item => {
const fn = () => {
const formData = new FormData()
formData.append('chunk', item.chunk)
formData.append('filename', item.fileName)
return axios({
url: '/single3',
method: 'post',
headers: { 'Content-Type': 'multipart/form-data' },
data: formData
}).then(res => {
if (res.data.code === 0) { //
if (this.percentCount === 0) {
this.percentCount = 100 / this.chunkList.length
}
this.percent += this.percentCount //
}
})
}
requestList.push(fn)
})
let i = 0 //
const send = async () => {
// if (' ') return
if (i >= requestList.length) {
//
return
}
await requestList[i]()
i++
send()
}
send() //
},
axios 부분 도 다음 과 같은 형식 으로 직접 쓸 수 있 습 니 다.
axios.post('/single3', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
모든 절편 발송 성공 후백 엔 드 인터페이스 에 따라 get 요청 을 하나 더 보 내 고 파일 의 hash 값 을 서버 에 전송 해 야 합 니 다.우 리 는 complete 방법 을 정의 하여 이 를 실현 합 니 다.비디오 파일 로 가정 합 니 다.
const complete = () => {
axios({
url: '/merge',
method: 'get',
params: { hash: this.hash }
}).then(res => {
if (res.data.code === 0) { //
this.videoUrl = res.data.path
}
})
}
이렇게 하면 파일 전송 에 성공 한 후에 페이지 에서 보 낸 동 영상 을 조회 할 수 있다.정지점 전송
우선 일시 정지 단추 텍스트 처리 입 니 다.필 터 를 사 용 했 습 니 다.upload 값 이 true 이면'일시 정지'를 표시 합 니 다.그렇지 않 으 면'계속'을 표시 합 니 다.
filters: {
btnTextFilter(val) {
return val ? ' ' : ' '
}
}
일시 정지 단 추 를 누 르 면 handle ClickBtn 방법 을 터치 합 니 다.
handleClickBtn() {
this.upload = !this.upload
//
if (this.upload) this.sendRequest()
}
절편 을 보 내 는 send 방법의 시작 에 if 를 추가 합 니 다(!this.upload)return,이 변 수 를 false 로 업로드 하면 계속 업로드 하지 않 습 니 다.일시 정지 가 끝 난 후에 도 계속 보 낼 수 있 도록 절편 을 성공 적 으로 보 낸 후에 이 절편 을 chunkList 배열 에서 this.chunkList.splice(index,1)를 삭제 해 야 합 니 다.코드 집합
<template>
<div id="app">
<!-- -->
<el-upload action drag :auto-upload="false" :show-file-list="false" :on-change="handleChange">
<i class="el-icon-upload"></i>
<div class="el-upload__text"> , <em> </em></div>
<div class="el-upload__tip" slot="tip"> 200M </div>
</el-upload>
<!-- -->
<div class="progress-box">
<span> :{{ percent.toFixed() }}%</span>
<el-button type="primary" size="mini" @click="handleClickBtn">{{ upload | btnTextFilter}}</el-button>
</div>
<!-- -->
<div v-if="videoUrl">
<video :src="videoUrl" controls />
</div>
</div>
</template>
<script>
import SparkMD5 from "spark-md5"
import axios from "axios"
export default {
name: 'App3',
filters: {
btnTextFilter(val) {
return val ? ' ' : ' '
}
},
data() {
return {
percent: 0,
videoUrl: '',
upload: true,
percentCount: 0
}
},
methods: {
async handleChange(file) {
if (!file) return
this.percent = 0
this.videoUrl = ''
// ArrayBuffer
const fileObj = file.raw
let buffer
try {
buffer = await this.fileToBuffer(fileObj)
} catch (e) {
console.log(e)
}
// (2M) ,
const chunkSize = 2097152,
chunkList = [], //
chunkListLength = Math.ceil(fileObj.size / chunkSize), //
suffix = /\.([0-9A-z]+)$/.exec(fileObj.name)[1] //
// hash
const spark = new SparkMD5.ArrayBuffer()
spark.append(buffer)
const hash = spark.end()
// , (chunk) (fileName)
let curChunk = 0 //
for (let i = 0; i < chunkListLength; i++) {
const item = {
chunk: fileObj.slice(curChunk, curChunk + chunkSize),
fileName: `${hash}_${i}.${suffix}` // hash_1.jpg
}
curChunk += chunkSize
chunkList.push(item)
}
this.chunkList = chunkList // sendRequest
this.hash = hash // sendRequest
this.sendRequest()
},
//
sendRequest() {
const requestList = [] //
this.chunkList.forEach((item, index) => {
const fn = () => {
const formData = new FormData()
formData.append('chunk', item.chunk)
formData.append('filename', item.fileName)
return axios({
url: '/single3',
method: 'post',
headers: { 'Content-Type': 'multipart/form-data' },
data: formData
}).then(res => {
if (res.data.code === 0) { //
if (this.percentCount === 0) { // chunkList percentCount
this.percentCount = 100 / this.chunkList.length
}
this.percent += this.percentCount //
this.chunkList.splice(index, 1) // chunk,
}
})
}
requestList.push(fn)
})
let i = 0 //
// , '/merge' , hash
const complete = () => {
axios({
url: '/merge',
method: 'get',
params: { hash: this.hash }
}).then(res => {
if (res.data.code === 0) { //
this.videoUrl = res.data.path
}
})
}
const send = async () => {
if (!this.upload) return
if (i >= requestList.length) {
//
complete()
return
}
await requestList[i]()
i++
send()
}
send() //
},
//
handleClickBtn() {
this.upload = !this.upload
//
if (this.upload) this.sendRequest()
},
// File ArrayBuffer
fileToBuffer(file) {
return new Promise((resolve, reject) => {
const fr = new FileReader()
fr.onload = e => {
resolve(e.target.result)
}
fr.readAsArrayBuffer(file)
fr.onerror = () => {
reject(new Error(' '))
}
})
}
}
}
</script>
<style scoped>
.progress-box {
box-sizing: border-box;
width: 360px;
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
padding: 8px 10px;
background-color: #ecf5ff;
font-size: 14px;
border-radius: 4px;
}
</style>
효 과 는 다음 그림 과 같 습 니 다:One More Thing
FormData
여기 서 데 이 터 를 보 내 는 데 FormData 를 사 용 했 습 니 다.인 코딩 형식 이'multipart/form-data'로 설정 되면 폼 과 같은 형식 을 사용 합 니 다.
FormData.append()
FormData 대상 에 존재 하 는 키 에 새 값 을 추가 합 니 다.키 가 존재 하지 않 으 면 이 키 를 추가 합 니 다.이 방법 은 3 개의 인자,formData.append(name,value,filename)를 전달 할 수 있 습 니 다.그 중에서 filename 은 선택 가능 한 매개 변수 로 서버 에 전 달 된 파일 이름 입 니 다.Blob 나 File 이 두 번 째 매개 변수 가 될 때 Blob 대상 의 기본 파일 이름 은'blob'입 니 다.File 대상 의 기본 파일 이름 은 이 파일 의 이름 입 니 다.
Vue 대 파일 업로드 와 정지점 속보 의 실현 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 Vue 대 파일 업로드 와 정지점 속보 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 부탁드립니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue Render 함수로 DOM 노드 코드 인스턴스 만들기render에서createElement 함수를 사용하여 DOM 노드를 만드는 것은 직관적이지 않지만 일부 독립 구성 요소의 디자인에서 특수한 수요를 충족시킬 수 있습니다.간단한 렌더링 예는 다음과 같습니다. 또한 v...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.