圖片預覽、壓縮、ajax上傳

       現在網頁的圖片交互越來越多,對於圖片的上傳、預覽、壓縮、裁剪等處理,都很常見,自己也查了很多資料,寫了一個很常見的圖片上傳實例,自己的項目中也經常使用,現在總結一下相關的技術,也供後面參考和改進。具體實現效果如下

 

相關內容

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很是好用。功能齊全,包括圖片的壓縮,裁剪,形狀裁剪等

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章