Vant實現(xiàn)上傳多個圖片或視頻,更改視頻預覽圖
更新時間:2022年10月20日 12:00:16 作者:Magic0901
這篇文章主要介紹了Vant實現(xiàn)上傳多個圖片或視頻,更改視頻預覽圖,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
Vant上傳多個圖片或視頻,更改視頻預覽圖
需求
- vant上傳多個視頻或圖片
- 圖片和視頻都有預覽圖
最終成果

過程
- 最開始是準備通過自定義預覽樣式,通過 preview-cover 插槽可以自定義覆蓋在預覽區(qū)域上方的內容。但問題是會修改每一個上傳的圖片和視頻,都添加上播放視頻的圖片,不能實現(xiàn)直接預覽圖片的效果
- 最終采用自定義單個圖片預覽
<van-uploader
accept="*"
v-model="imgList"
:after-read="afterRead"
:before-read="beforeRead"
preview-size='25vw'
@click-preview="handleclicksc"
:before-delete="afterDelete"
:preview-full-image="false"
:disabled="isUploading?true:false"
/>
<!--點擊圖片或視頻出現(xiàn)放大圖片或播放視頻的彈窗-->
<van-overlay :show="show" @click="show = false">
<div class="wrapper" >
<div class="img-block">
<img v-if="urlType==='image'" :src="url">
<video autoplay class="video" v-if="urlType==='video'" :src="url" controls></video>
</div>
<!--給視頻添加關閉圖標-->
<img v-if="urlType==='video'"
@click="show=false"
class="video-delete"
src="./close.png"
/>
</div>
</van-overlay>
data(){
return {
isUploading:false,
allInfoList:[],
url:'', //彈窗展示的圖片/視頻路徑
urlType:'', //彈窗展示的類型
}
},
watch: {
//監(jiān)聽allInfoList,根據allInfoList動態(tài)地修改文件列表
'allInfoList' () {
this.imgList = []
for (let item of this.allInfoList) {
let data = {
type: item.type,
name: item.originalName,
url: item.type === 'video' ? 'https://replacement.png' : 'https://' + item.fileUri
}
this.imgList.push(data)
}
}
},
methods:{
//限制上傳的內容為視頻或圖片
beforeRead (file) {
if (!file.type.startsWith('image') && !file.type.startsWith('video')) {
this.$toast('請上傳圖片或視頻')
return false
}
return true
},
afterRead (file) {
file.status = 'uploading'
file.message = '上傳中...'
//添加上傳狀態(tài),避免用戶在上傳未完成時點擊提交按鈕
this.isUploading = true
fileApi
.uploadFile(file.file)
.then(res => {
if (res.data.status === 'success') {
let fileDTO = response.data.fileDTO
//為返回的數(shù)據添加文件類型,后面依據此來判斷
if (file.file.type.startsWith('video')) {
fileDTO.type = 'video'
}
if (file.file.type.startsWith('image')) {
fileDTO.type = 'image'
}
//將返回的所有數(shù)據都保存起來(文件地址,文件名等)
this.allInfoList.push(fileDTO)
} else {
//上傳失敗要清空數(shù)組,不然失敗的文件依舊會展示
this.handleDelete(file.file.name)
}
file.status = ''
file.message = ''
this.isUploading = false
})
.catch((error) => {
console.log(error)
this.handleDelete(file.file.name)
file.status = ''
file.message = ''
this.isUploading = false
})
},
//根據文件名來查找到文件列表中要刪除的文件
handleDelete (name) {
this.imgList.forEach((item, index) => {
if (item.file.name === name) {
this.imgList.splice(index, 1)
}
})
},
//手動點擊刪除,修改包含所有信息的文件列表,通過watch根據該列表動態(tài)修改圖片文件列表
afterDelete (file) {
let name = file.name
this.allInfoList.forEach((item, index) => {
if (item.originalName === name) {
this.allInfoList.splice(index, 1)
}
})
return true
},
}
//取消掉組件自帶的點擊預覽功能,自己添加(系統(tǒng)自帶預覽點擊視頻時會先視頻的播放圖片)
handleclicksc (file) {
let name = file.name
for (let item of this.allInfoList) {
if (item.type === 'video' && item.originalName === name) {
this.url = this.getUrl(item.fileUri)
this.urlType = 'video'
this.show = true
}
if (item.type === 'image' && item.originalName === name) {
this.url = this.getUrl(item.fileUri)
this.urlType = 'image'
this.show = true
}
}
},
.wrapper {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.img-block {
position: relative;
img{
z-index: 99;
max-width: 100%;
height: auto;
object-fit: cover;
}
video{
width: 100%;
max-height: 100vh;
}
}
.video-delete{
width: 45px;
position: absolute;
top: 60px;
left: calc(100vw - 60px);
}
Vant上傳壓縮圖片;多圖片壓縮上傳

vant這種上傳方式是一個一個讀取的,需要將多文件上傳給禁用了,multiple=“false”——使用這個屬性
根據實際情況測試,7Mb圖片結果為100+kb,個別不代表全部,也有壓縮完為400多k的,壓縮后體積還是很小的,圖片也比較清晰,提前給大家一個參考
<van-uploader :after-read="afterRead" :accept="'image/*'" v-model="fileList" multiple="false"
:max-count="4"
/>
return {
// 圖片信息
files: {
name: "",
type: ""
}
// 單圖片上傳圖片
afterRead(file) {
this.files.name = file.file.name // 獲取文件名
this.files.type = file.file.type // 獲取類型
this.imgPreview(file.file)
},
// 如果是多圖片按照這種寫法即可,不過需要在上面將multiple設置為true
// afterRead(file,name) { 方法參數(shù)設置為多參數(shù)
// if (file instanceof Array && file.length) { // 判斷是否是多圖上傳 多圖則循環(huán)添加進去
// file.forEach(item => {
// this.imgPreview(item.file)
// })
// } else {
// this.imgPreview(file.file)
// }
// },
// 處理圖片
imgPreview(file) {
let self = this
let Orientation
//去獲取拍照時的信息,解決拍出來的照片旋轉問題 npm install exif-js --save 這里需要安裝一下包
Exif.getData(file, function() {
Orientation = Exif.getTag(this, 'Orientation')
})
// 看支持不支持FileReader
if (!file || !window.FileReader) return
if (/^image/.test(file.type)) {
// 創(chuàng)建一個reader
let reader = new FileReader()
// 將圖片2將轉成 base64 格式
reader.readAsDataURL(file)
// 讀取成功后的回調
reader.onloadend = function() {
let result = this.result
let img = new Image()
img.src = result
//判斷圖片是否大于500K,是就直接上傳,反之壓縮圖片
if (this.result.length <= 500 * 1024) {
// 上傳圖片
self.postImg(this.result)
} else {
img.onload = function() {
let data = self.compress(img, Orientation)
// 上傳圖片
self.postImg(data)
}
}
}
}
},
// 壓縮圖片
compress(img, Orientation) {
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')
//瓦片canvas
let tCanvas = document.createElement('canvas')
let tctx = tCanvas.getContext('2d')
// let initSize = img.src.length;
let width = img.width
let height = img.height
//如果圖片大于四百萬像素,計算壓縮比并將大小壓至400萬以下
let ratio
if ((ratio = (width * height) / 4000000) > 1) {
// console.log("大于400萬像素");
ratio = Math.sqrt(ratio)
width /= ratio
height /= ratio
} else {
ratio = 1
}
canvas.width = width
canvas.height = height
// 鋪底色
ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)
//如果圖片像素大于100萬則使用瓦片繪制
let count
if ((count = (width * height) / 1000000) > 1) {
// console.log("超過100W像素");
count = ~~(Math.sqrt(count) + 1) //計算要分成多少塊瓦片
// 計算每塊瓦片的寬和高
let nw = ~~(width / count)
let nh = ~~(height / count)
tCanvas.width = nw
tCanvas.height = nh
for (let i = 0; i < count; i++) {
for (let j = 0; j < count; j++) {
tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh)
ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh)
}
}
} else {
ctx.drawImage(img, 0, 0, width, height)
}
//修復ios上傳圖片的時候 被旋轉的問題
if (Orientation != '' && Orientation != 1) {
switch (Orientation) {
case 6: //需要順時針(向左)90度旋轉
this.rotateImg(img, 'left', canvas)
break
case 8: //需要逆時針(向右)90度旋轉
this.rotateImg(img, 'right', canvas)
break
case 3: //需要180度旋轉
this.rotateImg(img, 'right', canvas) //轉兩次
this.rotateImg(img, 'right', canvas)
break
}
}
//進行最小壓縮
let ndata = canvas.toDataURL('image/jpeg', 0.2)
tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0
console.log(ndata)
return ndata
},
// 旋轉圖片
rotateImg(img, direction, canvas) {
//最小與最大旋轉方向,圖片旋轉4次后回到原方向
const min_step = 0
const max_step = 3
if (img == null) return
//img的高度和寬度不能在img元素隱藏后獲取,否則會出錯
let height = img.height
let width = img.width
let step = 2
if (step == null) {
step = min_step
}
if (direction == 'right') {
step++
//旋轉到原位置,即超過最大值
step > max_step && (step = min_step)
} else {
step--
step < min_step && (step = max_step)
}
//旋轉角度以弧度值為參數(shù)
let degree = (step * 90 * Math.PI) / 180
let ctx = canvas.getContext('2d')
switch (step) {
case 0:
canvas.width = width
canvas.height = height
ctx.drawImage(img, 0, 0)
break
case 1:
canvas.width = height
canvas.height = width
ctx.rotate(degree)
ctx.drawImage(img, 0, -height)
break
case 2:
canvas.width = width
canvas.height = height
ctx.rotate(degree)
ctx.drawImage(img, -width, -height)
break
case 3:
canvas.width = height
canvas.height = width
ctx.rotate(degree)
ctx.drawImage(img, -width, 0)
break
}
},
//將base64轉換為文件
dataURLtoFile(dataurl) {
var arr = dataurl.split(','),
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], this.files.name, {
type: this.files.type
})
},
// 提交圖片到后端
postImg(base64) {
let file = this.dataURLtoFile(base64)
// 然后壓縮后的圖片放入集合,根據自己業(yè)務調用然后一起上傳
this.fileCompressList.push(file)
},
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue-cli對element-ui組件進行二次封裝的實戰(zhàn)記錄
組件類似于需要多個地方用到的方法,在Vue中組件就是一種復用(經常使用)一個功能的手段,下面這篇文章主要給大家介紹了關于Vue?element?ui二次封裝的相關資料,需要的朋友可以參考下2022-06-06

