Using cropper. js to encapsulate vue for online image cropping, cropper. jsvue
As shown below,
Github: demo download
Cropper. js
Github: cropper. js
Official website (demo)
Installing cropper. js
- Npm or bower Installation
npm install cropper# orbower install cropper
Clone download:
Git clone https://github.com/fengyuanchen/cropper.git
Reference cropper. js
Use cropper.js to follow 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>
Note: you must first introduce the jquery file before using the cropper. js plug-in.
Easy to use
Build the div container to be used
<!-- Wrap the image or canvas element with a block element (container) --><div> ![](picture.jpg)</div>
Add a container style to fill the entire container with img (important)
/* Limit image width to avoid overflow the container */img { max-width: 100%; /* This rule is very important, please do not ignore this! */}
Call the cropper. js method to initialize the control.
$('#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); }});
For details about other APIs, see github: cropper. js.
Encapsulated into a vue component
Issues to be resolved in encapsulation into vue Components
In the input box, click Select image and set the format and size of the selected image.
Reselect image Cropping
Confirm cropping and obtain base64 Format Image Information
Communication between non-Parent and Child Components
In the input box, click Select image and set the format and size of the selected image.
Create a hidden input tag and click this input tag to select images.
<! -- Input box --> <input id = "myCropper-input" type = "file": accept = "imgCropperData. accept "ref =" inputer "@ change =" handleFile "> // simulate clicking document. getElementById ('mycropper-input '). click ();
Bind a method to listen for content changes to the input file, obtain the uploaded file, and verify the format and size.
// ImgCropperData: {// accept: 'image/gif, image/jpeg, image/png, image/bmp ', //} handleFile (e) {let _ this = this; let inputDOM = this. $ refs. inputer; // get file data through DOM _ this. file = inputDOM. files [0]; // determine the file format if (_ this. imgCropperData. accept. indexOf (_ this. file. type) =-1) {_ this. $ Modal. error ({title: 'format error', content: 'The image format you selected is incorrect! '}); Return;} // determines the file size limit if (_ this. file. size> 5242880) {_ this. $ Modal. error ({title: 'exceeds limited', content: 'the image you selected is too large. Select an image within 5 MB! '}); Return;} var reader = new FileReader (); // convert the image to a base64 format reader. readAsDataURL (_ this. file); reader. onload = function () {_ this. imgCropperData. imgSrc = this. result; _ this. initCropper ();}}
Reselect image Cropping
After you select an image for the first time, you must reselect the image. In this case, you must replace the image in the cropping box () the method obtains the main information of the image. Now you need to rebuild the cropping box to solve the problem. View cropper. in the official demo provided by js, we found that the official method is to dynamically add and crop the container. Here we follow the official implementation.
// Initialize the cropping initCropper () {let _ this = this; // initialize the cropping area _ 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 ){}});}
Confirm cropping and obtain base64 Format Image Information
let $imgData = _this.imgObj.cropper('getCroppedCanvas')imgBase64Data = $imgData.toDataURL('image/png');
Construct the data to be uploaded
// Construct the data let formData = new FormData (); // capture the string let photoType = imgBase64Data. substring (imgBase64Data. indexOf (",") + 1); // hexadecimal conversion 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)
Communication between non-Parent and Child Components
In previous projects, parameters are often transmitted through communication between parent and child components. Generally, two methods are used.
Place parameters in the router, and then obtain them by calling route. params. xxx or route. query. xxx.
Communication through props
EventBus is used for communication between components.
Procedure
1. Declare A bus component for component B TO PASS Parameters to component
//bus.jsimport Vue from 'vue'; export default new Vue();
2. reference the bus component in component A and monitor its parameter changes in real time.
// 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. The bus component is referenced in component B TO PASS Parameters to component.
// B. vue // Pass Parameter Bus. $ emit ('gettarget', imgToken );
Refer:
Vue-$ on
Vue-$ emit
Vue. js Road (4) -- eventBus in vue2.0s implements sibling component communication
Complete vue graph selection plug-in code
<Template> <div class = "myCropper-container"> <div id = "myCropper-workspace"> <div class = "myCropper-words" v-show = "! ImgCropperData. imgSrc "> click the button to select an image for cropping </div> <div class =" myCropper-preview ": class =" isShort? 'Mycropper-preview-shport': 'mycropper-preview-long' "> <div class =" myCropper-preview-1 avatar-preview ">! [] (! ImgCropperData. imgUploadSrc? '/Images/thumbnail/IL': imgCropperData. imgUploadSrc) </div> <div class = "thumbnail-img.jpg avatar-preview">! [] (! ImgCropperData. imgUploadSrc? '/Images/thumbnail/IL': imgCropperData. imgUploadSrc) </div> <div class = "thumbnail-img.jpg avatar-preview">! [] (! ImgCropperData. imgUploadSrc? '/Images/thumbnail/IL': imgCropperData. imgUploadSrc) </div> <input id = "myCropper-input" type = "file": accept = "imgCropperData. accept "ref =" inputer "@ change =" handleFile "> <Button type =" ghost "class =" myCropper-btn "@ click =" btnClick "> select image </Button> <Button type = "primary" class = "myCropper-btn ": loading = "cropperLoading" @ click = "crop_ OK"> OK </Button> </div> </template> <script> var ezjs Util = Vue. ezjsUtil; import Bus from '. /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, // the uploaded file imgSrc: '', // read the imgfile base64 data stream imgUploadSrc:'', // The cropped imgfile base64 data stream}, imgOb J: null, hasSelectImg: false, cropperLoading: false, isShort: false, }}, created: function () {let _ this = this;}, mounted: function () {let _ this = this; // initialize the preview area 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;} // set the width and height of the maximum preview container ('width', previewWidth + 'px '); expires ('.mycropper-preview-1'}.css ('height', previewHeight + 'px '); // set the width and height of the medium preview container $ ('. myCropper-container. myCropper-preview .mycropper-preview-2'mirror.css ('width', (previewWidth/2) + 'px'); $ ('. myCropper-container. myCropper-preview .mycropper-preview-2'developer.css ('hei Ght ', (previewHeight/2) + 'px'); // you can specify the width and height of the minimum preview container ('. myCropper-container. myCropper-preview .mycropper-preview-3'mirror.css ('width', (previewWidth/4) + 'px'); $ ('. myCropper-container. myCropper-preview .mycropper-preview-3'hangzhou.css ('height', (previewHeight/4) + 'px') ;}, methods: {// click to select the image btnClick () {let _ this = this; // simulate input and click Select File document. getElementById ('mycropper-input '). click () ;}, // select The callback handleFile (e) {let _ this = this; let inputDOM = this. $ refs. inputer; // get file data through DOM _ this. file = inputDOM. files [0]; // determine the file format if (_ this. imgCropperData. accept. indexOf (_ this. file. type) =-1) {_ this. $ Modal. error ({title: 'format error', content: 'The image format you selected is incorrect! '}); Return;} // determines the file size limit if (_ this. file. size> 5242880) {_ this. $ Modal. error ({title: 'exceeds limited', content: 'the image you selected is too large. Select an image within 5 MB! '}); Return;} var reader = new FileReader (); // convert the image to a base64 format reader. readAsDataURL (_ this. file); reader. onload = function () {_ this. imgCropperData. imgSrc = this. result; _ this. initCropper () ;}}, // initialize cut initCropper () {let _ this = this; // initialize Crop Region _ 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;}, // confirm crop_ OK () {let _ this = this, imgToken = null, imgBase64Data = null; // determine whether to select the image if (_ this. hasSele CtImg = false) {_ this. $ Modal. error ({title: 'cropping failed', content: 'select an image and then crop it! '}); Return false;} // The confirmation button is unavailable _ this. cropperLoading = true; let $ imgData = _ this. imgObj. cropper ('getcroppedcanvas ') imgBase64Data = $ imgData. toDataURL ('image/png '); // construct the data of the uploaded image let formData = new FormData (); // capture the string let photoType = imgBase64Data. substring (imgBase64Data. indexOf (",") + 1); // hexadecimal conversion const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {const byteCharacters = atob (b64Da Ta); 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 (byteArray S, {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 upload $. ajax ({url: _ this. $ nfs. uploadUrl, method: 'post', data: formData, // The default value is true. If it is set to false, it will not be executed until the ajax request ends (the function is called back. ajax (...) the following code async: false ,// The following three items, because FormData is directly used as the data, contentType is automatically set, and jquery does not need to perform further data processing (serialization ). Cache: false, contentType: false, processData: false, type: _ this. imgType, success: function (res) {let imgToken = res. data. token; _ this. cropperLoading = false; // pass the parameter Bus. $ emit ('gettarget', imgToken);}, error: function (error) {_ this. cropperLoading = false; _ this. $ Modal. error ({title: 'System error', content: 'Please crop the image and upload it again! '}) ;}}}}}}</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;} // The prompt text for cropping an image that is not selected. myCropper-container # myCropper-workspace. myCropper-words {text-align: center; font-size: 18px; padding-top: 180px;} // preview area of the cropped image. 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 # dddee1; img {width: 100%; height: 100% ;}}. myCropper-container. myCropper-preview. the myCropper-preview-2 {margin-top: 20px; border-radius: 5px; overflow: hidden; border: 1px solid # dddee1; box-shadow: 3px 3px # dddee1; img {width: 100%; height: 100% ;}}. myCropper-container. myCropper-preview. the myCropper-preview-3 {margin-top: 20px; border-radius: 5px; overflow: hidden; border: 1px solid # dddee1; box-shadow: 3px 3px # dddee1; img {width: 100%; height: 100%;} // button. myCropper-btn {float: left; margin-top: 20px; margin-right: 10px ;}</style>
BY-LucaLJX
Github: lucaljx
Summary
The above section is a cropper-based introduction. js-encapsulated vue to implement the online image cropping component function. I hope it will help you. If you have any questions, please leave a message and I will reply to you in a timely manner. Thank you very much for your support for the help House website!