使用FormData數據做圖片上傳: new FormData() canvas實現圖片壓縮
ps: 千萬要使用append不要用set 蘋果ios有兼容問題導致數據獲取不到,需要后台接口支持formData數據 Content-Type: multipart/form-data
正確的打開方式:formdata.append('file', file)
錯誤的打開方式:formData.set(name,value)
//html代碼
<div class="sendImage" slot="label">
<input type="file" name="file" accept="image/*" ref="ndImgUpload"
class="upload_input" @change="imgSelectChange">
</div>
//**************javascript代碼 Begin**********************
//************* tool.js文件 canvas實現圖片壓縮***********
// 用於壓縮圖片的canvas
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d');
// 瓦片canvas
let tCanvas = document.createElement("canvas");
let tctx = tCanvas.getContext("2d");
// /**
// * ************ js圖片壓縮類*****************
// */
export function compress (img) {
let initSize = img.src.length;
let width = img.width;
let height = img.height;
//如果圖片大於四百萬像素,計算壓縮比並將大小壓至400萬以下
let ratio;
if ((ratio = width * height / 4000000) > 1) {
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) {
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);
}
//進行壓縮toDataURL:值越小,壓縮力度越大
let ndata = canvas.toDataURL('image/jpeg', 0.7);
console.log('壓縮前:' + initSize);
console.log('壓縮后:' + ndata.length);
console.log('壓縮率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");
tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
return ndata;
}
/**
* 將以base64的圖片url數據轉換為Blob
* @param urlData
* 用url方式表示的base64圖片數據
*/
export function convertBase64UrlToBlob (urlData) {
let arr = urlData.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = window.atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type: mime});
}
/**
* ***********業務代碼開始************
*/
import {compress, convertBase64UrlToBlob} from 'utils/tool'
const UPLOAD_IMG_SIZE = 10 //圖片上傳大小不能大於10M
const IMG_NEED_COMPRESS_SIZE = 0.5 //圖片大小<=0.5M,則不壓縮,直接上傳
const SELECT_IMG_QUANTITY = 9 //發送消息圖片最多選9張
// *************vue代碼 ***************
methods:{
imgSelectChange (e) {
this.$vux.loading.show({
text: 'Loading'
})
let file = e.target
setTimeout(() => { //加500ms定時器是為了防止大質量圖片上傳會造成卡頓loading會延遲執行
this.sendImgIndex = 0
if (file.files.length > SELECT_IMG_QUANTITY) {
this.$vux.loading.hide()
return this.$vux.alert.show({
title: '提示',
content: '最多選9張圖片',
onHide () {
file.value = ''
}
})
}
for (let obj of Array.from(file.files)) {
if (!/\/(?:jpeg|png|gif|jpg)/i.test(obj.type)) {
this.$vux.loading.hide()
return this.$vux.alert.show({
title: '提示',
content: `${obj.name}不是圖片文件類型`,
onHide () {
file.value = ''
}
})
}
let calcSize = obj.size / 1024 / 1024
if (calcSize > UPLOAD_IMG_SIZE) {
this.$vux.loading.hide()
return this.$vux.alert.show({
title: '提示',
content: `圖片大小不能大於${UPLOAD_IMG_SIZE}M`,
onHide () {
file.value = ''
}
})
}
}
const imgLen = file.files.length
this.eachSendImg(file.files, file, (data) => {
//msgType 0系統 1文字 2圖片 3音頻 4視頻 5回撤
this.sendMsgHandle(2, data, () => {
this.sendImgIndex === imgLen && this.$vux.loading.hide()
}, () => {
this.sendImgIndex === imgLen && this.$vux.loading.hide()
this.$vux.alert.show({
title: '提示',
content: `圖片${file.files[this.sendImgIndex - 1].name}發送消息失敗`
});
})
}, (err) => {
})
}, 500)
},
eachSendImg (files, input, success, error) {
if (!files.length) return
let that = this
let args = arguments
that.sendImg(files[that.sendImgIndex]).then(data => {
success(data)
that.sendImgIndex++
files[that.sendImgIndex] ? that.eachSendImg.apply(that, args) : input.value = ''
}).catch(err => {
that.$vux.loading.hide()
let txt_tip = err.msg === 'FILE_WRONG_SIZE' ? `圖片${files[that.sendImgIndex].name}文件過大,上傳失敗`
: `圖片${files[that.sendImgIndex].name}上傳失敗`;
that.$vux.alert.show({
title: '提示',
content: txt_tip,
onHide () {
error(err)
that.sendImgIndex++
if (files[that.sendImgIndex]) {
that.$vux.loading.show({
text: 'Loading'
})
that.eachSendImg.apply(that, args)
} else {
input.value = ''
}
}
})
})
},
sendImg (file) {
let formdata = new FormData(); // FormData 對象
let that = this
return new Promise((resolve, reject) => {
if (file.size / 1024 / 1024 <= IMG_NEED_COMPRESS_SIZE) {
formdata.append('file', file)
that.sendImgAjax(formdata).then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
return;
}
let reader = new FileReader();
reader.onload = function () {
let result = this.result;
let img = new Image();
img.src = result;
// 圖片加載完畢之后進行壓縮,然后上傳
if (img.complete) {
let data = compress(img);
let blob = convertBase64UrlToBlob(data);
formdata.append("file", blob, "file_" + Date.parse(new Date()) + ".jpg"); // 文件對象
that.sendImgAjax(formdata).then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
img = null;
} else {
img.onload = () => {
let data = compress(img);
let blob = convertBase64UrlToBlob(data);
formdata.append("file", blob, "file_" + Date.parse(new Date()) + ".jpg"); // 文件對象
that.sendImgAjax(formdata).then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
img = null;
};
}
}
reader.readAsDataURL(file);
})
},
sendImgAjax (formData) {
return new Promise((resolve, reject) => {
getData.common.form_uploadImg({
data: formData,
sucCb (data) {
resolve(data)
},
failCb (err) {
reject(err)
}
})
})
},
sendMsgHandle (type, msg, success, error) {//發送消息
if (!this.inputVal.trim() && !msg) return this.$vux.toast.text('消息內容不能為空');
this.disabled = true
this.$vux.loading.show({
text: 'Loading'
})
if (this.query.groupId) {
let that = this
getData.doctor.group_chat_send_msg({
params: {
gid: that.query.groupId,
//msg{1 || 0} :如果是圖片上傳,數據轉為字符串,包含寬高url,msgType
msg: msg ? JSON.stringify(msg) : that.inputVal,
type //msgType 0系統 1文字 2圖片 3音頻 4視頻 5回撤
},
sucCb (data) {
msg && (data.msg = JSON.parse(data.msg)) //如果是圖片上傳,msg消息數據為對象轉的字符串
that.data.push({
chatid: data.uid,
from: data.uid,
content: msg ? data.msg.url : data.msg,
width: msg ? data.msg.width : 0,
height: msg ? data.msg.height : 0,
create_time: data.date,
avatar: data.pic,
name: data.nick,
group_id: data.gid,
msg_id: data.id,
msg_type: data.type
})
that.addPrevTimeData()
that.setLocalData(that.query.groupId, that.data.slice(-1))
type !== 2 && that.$vux.loading.hide()
that.disabled = false
that.inputVal = ''
success && success()
},
failCb (err) {
type !== 2 && that.$vux.loading.hide()
that.disabled = false
let overtime = err.code * 1 === 0
if (that.inGoBackError(err.code) || overtime) {
type === 2 && that.$vux.loading.hide()
that.$vux.alert.show({
title: '提示',
content: overtime ? '發送失敗,請檢查網絡' : err.code === 'USER_NOT_IN_GROUP' ? '您已被移出群聊' : err.msg,
onHide () {
!overtime && that.$router.replace({
path: '/spa/msgGroup'
})
}
});
} else if (type === 2) {
error && error()
} else {
that.$vux.loading.hide()
that.$vux.alert.show({
title: '提示',
content: '消息發送失敗'
});
}
}
})
}
}
}
