現在網頁的圖片交互越來越多,對於圖片的上傳、預覽、壓縮、裁剪等處理,都很常見,自己也查了很多資料,寫了一個很常見的圖片上傳實例,自己的項目中也經常使用,現在總結一下相關的技術,也供後面參考和改進。具體實現效果如下
相關內容
1.圖片預覽
通常上傳文件使用input表單來,就是隻能顯示文件名,現在基本都是通過圖片預覽,讓用戶更好的操作。實現預覽原理就是將input獲取到的文件通過createObjectURL轉化成img的src路徑,實現圖片的展示
<input type="file" accept="image/*" id="inputfile" @change="preImg('inputfile')" >
getFileUrl:function (id) {//根據輸入框id 生成圖片src
console.log(document.getElementById(id).files[0]);
var url;
if (navigator.userAgent.indexOf("MSIE")>=1) { // IE
url = document.getElementById("inputfile").value;
} else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox
url = window.URL.createObjectURL(document.getElementById(id).files.item(0));
} else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome
url = window.URL.createObjectURL(document.getElementById(id).files.item(0));
}else {
url = window.webkitURL.createObjectURL(document.getElementById(id).files[0]);
}
return url;
},
2.圖片的上傳
和文件上傳一樣,需要通過formdata進行上傳,jquery的ajax上傳文件還需要設置mimeType,還需要取消type:'json',因此成功後的內容爲字符串格式,需要重新轉化成json,裏面的subFile是一個存放文件的數組,每個值是input的files值==>document.getElementById(id).files.item(0)或者document.getElementById(id).files[0],根據不同瀏覽器不同,見上圖。
var formData = new FormData();
for(var k in this.subFile){ //文件數組
formData.append('pPath',this.subFile[k]);
}
formData.append('type',this.addType);
formData.append('message',this.addContent);
formData.append('userNo',JSON.parse(localStorage.getItem('skyUser')).userNo);
formData.append('token',localStorage.getItem('skyUsertoken'));
$.ajax({
type:"post",
url:vm.path+"makeStatement.json",
data:formData,
cache: false,
contentType: false,
processData:false,
mimeType:"multipart/form-data",
success:function(data){
var a=JSON.parse(data);
}});
3.圖片壓縮
基於現在手機拍照,照片都很大,嚴重影響上傳速度,因此需要對圖片進行壓縮上傳,具體也是基於canvas的畫圖canvas.toDataURL('image/jpeg', quality);下面方法就是通過img的src進行圖片壓縮,obj設置壓縮後寬高,callback函數返回圖片的base64值。
dealImage: function (path, obj, callback) {
var img = new Image();
img.src = path;
img.onload = function () {
var that = this;
// 默認按比例壓縮
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.9;
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 創建屬性節點
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 圖像質量
if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
quality = obj.quality;
}
// quality值越小,所繪製出的圖像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回調函數返回base64的值
callback(base64);
}
},
壓縮後的圖片爲base64則需要轉化成blob對象才能進行上傳,具體實現如下方法
convertBase64UrlToBlob: function (urlData) {
var bytes = window.atob(urlData.split(',')[1]); //去掉url的頭,並轉換爲byte
//處理異常,將ascii碼小於0的轉換爲大於0
var ab = new ArrayBuffer(bytes.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], {type: 'image/png'});
},
因此在壓縮的callback裏調用
let vm = this;
vm.dealImage(src,{width:300},function (base) {
console.log(vm.convertBase64UrlToBlob(base));
vm.subFile.push(vm.convertBase64UrlToBlob(base))
console.log(vm.imgs);
})
完整代碼如下,複製出來直接使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
</head>
<style>
.addItem{
width: 100%;
height: 100%;
position: fixed;
top: 0;
z-index: 9999;
font-size: 0.3rem;
background-color: #fff;
overflow: scroll;
}
.addItem .add_content{
border-bottom: dashed #fda7f7 1px;
}
.cream {
position: relative;
display: inline-block;
overflow: hidden;
text-decoration: none;
text-indent: 0;
margin-top: 10px;
margin-left: 10px;
width: 80px;
height: 80px;
border-radius: 5px;
border: solid 1px #eee;
}
.cream .addimg{
font-size: 30px;
color: #555;
text-align: center;
line-height: 80px;
}
.cream input {
position: absolute;
display: block;
font-size: 60px;
right: 0;
top: 0;
opacity: 0;
}
.cream:hover {
text-decoration: none;
}
.deleteImg{
position: absolute;
right: 2px;
top: 2px;
width: 20px;
height: 20px;
background: rgba(150,150,150,0.5);
text-align: center;
line-height: 20px;
font-size: 20px;
color: #fff;
}
</style>
<body>
<div id="main">
<div id="smallimages">
<div class="cream" v-for="(img,n) in imgs" :key="n">
<div class="deleteImg" @click="deleteImg(n)">-</div>
<img :src="img" width="80px" height="80px">
</div>
<div class="cream" v-show="cream">
<div class="addimg">+</div>
<input type="file" accept="image/*" id="inputfile" @change="preImg('inputfile')" >
</div>
</div>
</div>
</body>
<script src="http://code.jquery.com/jquery-1.4.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#main",
data:function() {
return {
addType: '說說',
cream:true,
imgs:[],//顯示的圖片
subFile:[],//上傳的圖片
}
},
watch:{//設置最多上傳9張
imgs:function (val,old) {
if(val.length>=9){
this.cream = false
}else {
this.cream = true
}
}
},
methods:{
preImg:function (id) {
var vm = this;
var src = this.getFileUrl(id);
vm.imgs.push(src);
console.log( this.getFileUrl(id));
vm.dealImage(src,{width:300},function (base) {
console.log(vm.convertBase64UrlToBlob(base));
vm.subFile.push(vm.convertBase64UrlToBlob(base))
console.log(vm.imgs);
})
},
getFileUrl:function (id) {//根據輸入框id 生成圖片src
console.log(document.getElementById(id).files[0]);
var url;
if (navigator.userAgent.indexOf("MSIE")>=1) { // IE
url = document.getElementById("inputfile").value;
} else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox
url = window.URL.createObjectURL(document.getElementById(id).files.item(0));
} else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome
url = window.URL.createObjectURL(document.getElementById(id).files.item(0));
}else {
url = window.webkitURL.createObjectURL(document.getElementById(id).files[0]);
}
return url;
},
dealImage: function (path, obj, callback) {//進行圖片壓縮
var img = new Image();
img.src = path;
img.onload = function () {
var that = this;
// 默認按比例壓縮
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.9;
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 創建屬性節點
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 圖像質量
if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
quality = obj.quality;
}
// quality值越小,所繪製出的圖像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回調函數返回base64的值
callback(base64);
}
},
convertBase64UrlToBlob: function (urlData) {
var bytes = window.atob(urlData.split(',')[1]); //去掉url的頭,並轉換爲byte
//處理異常,將ascii碼小於0的轉換爲大於0
var ab = new ArrayBuffer(bytes.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], {type: 'image/png'});
},
deleteImg:function (n) {
console.log(n);
this.imgs.splice(n,1);
this.subFile.splice(n,1);
console.log(this.imgs)
console.log(this.subFile)
},
subm:function () {
var vm = this;
var formData = new FormData();
for(var k in this.subFile){ //文件數組
formData.append('pPath',this.subFile[k]);
}
formData.append('type',this.addType);
$.ajax({
type:"post",
url:"",
data:formData,
cache: false,
contentType: false,
processData:false,
mimeType:"multipart/form-data",
success:function(data){
var a=JSON.parse(data);
console.log(a);
}});
}
},
})
</script>
</html>
通過控制檯可以打印出壓縮前後的圖片大小
最後分享一個基於vue的圖片上傳插件 vue-corppa 官網鏈接:https://zhanziyang.github.io/vue-croppa/#/quick-start很是好用。功能齊全,包括圖片的壓縮,裁剪,形狀裁剪等