基於cropper.js封裝vue實現線上圖片裁剪組件功能,cropper.jsvue

來源:互聯網
上載者:User

基於cropper.js封裝vue實現線上圖片裁剪組件功能,cropper.jsvue

如下所示,

github:demo下載

cropper.js

github:cropper.js

官網(demo)

cropper.js 安裝

  • npm或bower安裝
npm install cropper# orbower install cropper

clone下載:

git clone https://github.com/fengyuanchen/cropper.git

引用cropper.js

主要引用cropper.js跟cropper.css兩個檔案

<script src="/path/to/jquery.js"></script><!-- jQuery is required --><link href="/path/to/cropper.css" rel="external nofollow" rel="stylesheet"><script src="/path/to/cropper.js"></script>

注意:必須先引入jquery檔案,才能使用cropper.js外掛程式

簡單使用

構建所要用到的div容器

<!-- Wrap the image or canvas element with a block element (container) --><div> ![](picture.jpg)</div>

添加容器的樣式,讓img填充滿整個容器(很重要)

/* Limit image width to avoid overflow the container */img { max-width: 100%; /* This rule is very important, please do not ignore this! */}

調用cropper.js方法,初始化控制項

$('#image').cropper({ aspectRatio: 16 / 9, crop: function(e) { // Output the result data for cropping image. console.log(e.x); console.log(e.y); console.log(e.width); console.log(e.height); console.log(e.rotate); console.log(e.scaleX); console.log(e.scaleY); }});

其他詳細api請參考:github:cropper.js

封裝成vue組件

封裝成vue組件中需解決的問題

  • cropper.js相關

類比input框點擊選擇圖片並對選擇的圖片進行格式、大小限制

重新選擇圖片裁剪

確認裁剪並擷取base64格式的圖片資訊

  • vue相關

非父子組件之間的通訊問題

類比input框點擊選擇圖片並對選擇的圖片進行格式、大小限制

構建一個隱藏的input標籤,然後類比點擊此input,從而達到能選擇圖片的功能

<!-- input框 --><input id="myCropper-input" type="file" :accept="imgCropperData.accept" ref="inputer" @change="handleFile">//類比點擊document.getElementById('myCropper-input').click();

給input綁定一個監聽內容變化的方法,拿到上傳的檔案,並進行格式、大小校正

// imgCropperData: {// accept: 'image/gif, image/jpeg, image/png, image/bmp',// }handleFile (e) { let _this = this; let inputDOM = this.$refs.inputer; // 通過DOM取檔案資料 _this.file = inputDOM.files[0]; // 判斷檔案格式 if (_this.imgCropperData.accept.indexOf(_this.file.type) == -1) { _this.$Modal.error({  title: '格式錯誤',  content: '您選擇的圖片格式不正確!' }); return; } // 判斷檔案大小限制 if (_this.file.size > 5242880) { _this.$Modal.error({  title: '超出限制',  content: '您選擇的圖片過大,請選擇5MB以內的圖片!' }); return; } var reader = new FileReader(); // 將圖片將轉成 base64 格式 reader.readAsDataURL(_this.file); reader.onload = function () { _this.imgCropperData.imgSrc = this.result; _this.initCropper(); }}

重新選擇圖片裁剪

當第一次選擇圖片之後,肯定會面臨需要重選圖片的問題,那麼就會面臨如何替換掉裁剪框中的圖片,上面的步驟選擇了圖片後通過FileRender()方法拿到了圖片的主要資訊,現在就需要重新構建裁剪框就可以解決問題了,查看cropper.js給出的官方demo,發現官方是使用動態添加裁剪容器的方法,進行操作的,這裡我們仿照官方進行實現。

// 初始化剪下 initCropper () { let _this = this; // 初始化裁剪地區 _this.imgObj = $('![](' + _this.imgCropperData.imgSrc + ')'); let $avatarPreview = $('.avatar-preview'); $('#myCropper-workspace').empty().html(_this.imgObj); _this.imgObj.cropper({  aspectRatio: _this.proportionX / _this.proportionY,  preview: $avatarPreview,  crop: function(e) {  } }); }

確認裁剪並擷取base64格式的圖片資訊

let $imgData = _this.imgObj.cropper('getCroppedCanvas')imgBase64Data = $imgData.toDataURL('image/png');

構造用於上傳的資料

// 構造上傳圖片的資料let formData = new FormData();// 截取字串let photoType = imgBase64Data.substring(imgBase64Data.indexOf(",") + 1);//進位轉換const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => { const byteCharacters = atob(b64Data); const byteArrays = []; for(let offset = 0; offset < byteCharacters.length; offset += sliceSize) { const slice = byteCharacters.slice(offset, offset + sliceSize); const byteNumbers = new Array(slice.length); for(let i = 0; i < slice.length; i++) {  byteNumbers[i] = slice.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } const blob = new Blob(byteArrays, { type: contentType }); return blob;}const contentType = 'image/jepg';const b64Data2 = photoType;const blob = b64toBlob(b64Data2, contentType);formData.append("file", blob, "client-camera-photo.png")formData.append("type", _this.imgType)

非父子組件之間的通訊問題

在之前的項目中,常用到父子組件之間的通訊傳參,一般用兩種方法

在router裡面放置參數,然後通過調用route.params.xxx或者route.query.xxx進行擷取

通過props進行通訊

這裡我們使用eventBus進行組件之間的通訊

步驟

1.聲明一個bus組件用於B組件把參數傳遞給A組件

//bus.jsimport Vue from 'vue'; export default new Vue();

2.在A組件中引用bus組件,並即時監聽其參數變化

// A.vueimport Bus from '../../components/bus/bus.js'export default { components: { Bus }, data () {}, created: function () { Bus.$on('getTarget', imgToken => {   var _this = this;  console.log(imgToken);  ...  });  }}

3.B組件中同樣引用bus組件,來把參數傳給A組件

// B.vue// 傳參Bus.$emit('getTarget', imgToken);

參考:

vue-$on
vue-$emit
vue.js之路(4)——vue2.0s中eventBus實現兄弟組件通訊

vue選圖外掛程式完整代碼

<template> <div class="myCropper-container"> <div id="myCropper-workspace">  <div class="myCropper-words" v-show="!imgCropperData.imgSrc">請點擊按鈕選擇圖片進行裁剪</div> </div> <div class="myCropper-preview" :class="isShort ? 'myCropper-preview-short' : 'myCropper-preview-long'">  <div class="myCropper-preview-1 avatar-preview">  ![](!imgCropperData.imgUploadSrc ? '/images/thumbnail/thumbnail-img.jpg' : imgCropperData.imgUploadSrc)  </div>  <div class="myCropper-preview-2 avatar-preview">  ![](!imgCropperData.imgUploadSrc ? '/images/thumbnail/thumbnail-img.jpg' : imgCropperData.imgUploadSrc)  </div>  <div class="myCropper-preview-3 avatar-preview">  ![](!imgCropperData.imgUploadSrc ? '/images/thumbnail/thumbnail-img.jpg' : imgCropperData.imgUploadSrc)  </div>  <input id="myCropper-input" type="file" :accept="imgCropperData.accept" ref="inputer" @change="handleFile">  <Button type="ghost" class="myCropper-btn" @click="btnClick">選擇圖片</Button>  <Button type="primary" class="myCropper-btn" :loading="cropperLoading" @click="crop_ok">確認</Button> </div> </div></template><script> var ezjsUtil = Vue.ezjsUtil; import Bus from './bus/bus.js'  export default { components: { Bus }, props: {  imgType: {  type: String  },  proportionX: {  type: Number  },  proportionY: {  type: Number  } }, data () {  return {  imgCropperData: {   accept: 'image/gif, image/jpeg, image/png, image/bmp',   maxSize: 5242880,   file: null, //上傳的檔案   imgSrc: '', //讀取的img檔案base64資料流   imgUploadSrc: '', //裁剪之後的img檔案base64資料流  },  imgObj: null,  hasSelectImg: false,  cropperLoading: false,  isShort: false,  } }, created: function () {  let _this = this; }, mounted: function () {  let _this = this;  // 初始化預覽地區  let maxWidthNum = Math.floor(300 / _this.proportionX);  let previewWidth = maxWidthNum * _this.proportionX;  let previewHeight = maxWidthNum * _this.proportionY;  if (previewWidth / previewHeight <= 1.7) {  previewWidth = previewWidth / 2;  previewHeight = previewHeight / 2;  _this.isShort = true;  }  // 設定最大預覽容器的寬高  $('.myCropper-preview-1').css('width', previewWidth + 'px');  $('.myCropper-preview-1').css('height', previewHeight + 'px');  // 設定中等預覽容器的寬高  $('.myCropper-container .myCropper-preview .myCropper-preview-2').css('width',( previewWidth / 2) + 'px');  $('.myCropper-container .myCropper-preview .myCropper-preview-2').css('height', (previewHeight / 2) + 'px');  // 設定最小預覽容器的寬高  $('.myCropper-container .myCropper-preview .myCropper-preview-3').css('width',( previewWidth / 4) + 'px');  $('.myCropper-container .myCropper-preview .myCropper-preview-3').css('height', (previewHeight / 4) + 'px'); }, methods: {  // 點擊選擇圖片  btnClick () {  let _this = this;  // 類比input點擊選擇檔案  document.getElementById('myCropper-input').click();  },  // 選擇之後的回調  handleFile (e) {  let _this = this;  let inputDOM = this.$refs.inputer;  // 通過DOM取檔案資料  _this.file = inputDOM.files[0];  // 判斷檔案格式  if (_this.imgCropperData.accept.indexOf(_this.file.type) == -1) {   _this.$Modal.error({   title: '格式錯誤',   content: '您選擇的圖片格式不正確!'   });   return;  }  // 判斷檔案大小限制  if (_this.file.size > 5242880) {   _this.$Modal.error({   title: '超出限制',   content: '您選擇的圖片過大,請選擇5MB以內的圖片!'   });   return;  }  var reader = new FileReader();  // 將圖片將轉成 base64 格式  reader.readAsDataURL(_this.file);  reader.onload = function () {   _this.imgCropperData.imgSrc = this.result;   _this.initCropper();  }  },  // 初始化剪下  initCropper () {  let _this = this;  // 初始化裁剪地區  _this.imgObj = $('![](' + _this.imgCropperData.imgSrc + ')');  let $avatarPreview = $('.avatar-preview');  $('#myCropper-workspace').empty().html(_this.imgObj);  _this.imgObj.cropper({   aspectRatio: _this.proportionX / _this.proportionY,   preview: $avatarPreview,   crop: function(e) {   }  });  _this.hasSelectImg = true;  },  // 確認  crop_ok () {  let _this = this, imgToken = null, imgBase64Data = null;  // 判斷是否選擇圖片  if (_this.hasSelectImg == false) {   _this.$Modal.error({   title: '裁剪失敗',   content: '請選擇圖片,然後進行裁剪操作!'   });   return false;  }  // 確認按鈕不可用  _this.cropperLoading = true;  let $imgData = _this.imgObj.cropper('getCroppedCanvas')  imgBase64Data = $imgData.toDataURL('image/png');   // 構造上傳圖片的資料  let formData = new FormData();  // 截取字串  let photoType = imgBase64Data.substring(imgBase64Data.indexOf(",") + 1);  //進位轉換    const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {     const byteCharacters = atob(b64Data);     const byteArrays = [];     for(let offset = 0; offset < byteCharacters.length; offset += sliceSize) {      const slice = byteCharacters.slice(offset, offset + sliceSize);      const byteNumbers = new Array(slice.length);      for(let i = 0; i < slice.length; i++) {       byteNumbers[i] = slice.charCodeAt(i);      }      const byteArray = new Uint8Array(byteNumbers);      byteArrays.push(byteArray);     }     const blob = new Blob(byteArrays, {      type: contentType     });     return blob;  }  const contentType = 'image/jepg';    const b64Data2 = photoType;  const blob = b64toBlob(b64Data2, contentType);  formData.append("file", blob, "client-camera-photo.png")  formData.append("type", _this.imgType)  // ajax上傳  $.ajax({     url: _this.$nfs.uploadUrl,     method: 'POST',     data: formData,     // 預設為true,設為false後直到ajax請求結束(調完回掉函數)後才會執行$.ajax(...)後面的代碼     async: false,     // 下面三個,因為直接使用FormData作為資料,contentType會自動化佈建,也不需要jquery做進一步的資料處理(序列化)。     cache: false,     contentType: false,   processData: false,   type: _this.imgType,     success: function(res) {   let imgToken = res.data.token;   _this.cropperLoading = false;   // 傳參   Bus.$emit('getTarget', imgToken);      },     error: function(error) {   _this.cropperLoading = false;   _this.$Modal.error({    title: '系統錯誤',    content: '請重新裁剪圖片進行上傳!'   });     }    });  }, } }</script><style lang="less" scoped> .myCropper-container { height: 400px; } .myCropper-container #myCropper-input { width: 0px; height: 0px; } .myCropper-container #myCropper-workspace { width: 500px; height: 400px; border: 1px solid #dddee1; float: left; } // 裁剪圖片未選擇圖片的提示文字 .myCropper-container #myCropper-workspace .myCropper-words{ text-align: center; font-size: 18px; padding-top: 180px; } // 裁剪圖片的預覽地區 .myCropper-container .myCropper-preview-long { width: 300px; } .myCropper-container .myCropper-preview-short { width: 200px; } .myCropper-container .myCropper-preview { float: left; height: 400px; margin-left: 10px; } .myCropper-container .myCropper-preview .myCropper-preview-1 { border-radius: 5px; overflow: hidden; border: 1px solid #dddee1; box-shadow: 3px 3px 3px #dddee1; img {  width: 100%;  height: 100%; } } .myCropper-container .myCropper-preview .myCropper-preview-2 { margin-top: 20px; border-radius: 5px; overflow: hidden; border: 1px solid #dddee1; box-shadow: 3px 3px 3px #dddee1; img {  width: 100%;  height: 100%; } } .myCropper-container .myCropper-preview .myCropper-preview-3 { margin-top: 20px; border-radius: 5px; overflow: hidden; border: 1px solid #dddee1; box-shadow: 3px 3px 3px #dddee1; img {  width: 100%;  height: 100%; } } // 按鈕 .myCropper-btn { float: left; margin-top: 20px; margin-right: 10px; }</style>

BY-LucaLJX

github: lucaljx

總結

以上所述是小編給大家介紹的基於cropper.js封裝vue實現線上圖片裁剪組件功能,希望對大家有所協助,如果大家有任何疑問請給我留言,小編會及時回複大家的。在此也非常感謝大家對幫客之家網站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.