基于cropper.js封装vue实现在线图片裁剪组件功能
效果图如下所示,
cropper.js
cropper.js 安装
- npm或bower安装
npm install cropper # or bower install cropper
clone下载:
git clone
引用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请参考:
封装成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给出的,发现官方是使用动态添加裁剪容器的方法,进行操作的,这里我们仿照官方进行实现。
// 初始化剪切 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.js import vue from 'vue'; export default new vue();
2.在a组件中引用bus组件,并实时监听其参数变化
// a.vue import 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.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
总结
以上所述是小编给大家介绍的基于cropper.js封装vue实现在线图片裁剪组件功能,希望对大家有所帮助
推荐阅读
-
基于asp.net实现图片在线上传并在线裁剪功能
-
vue-cli结合Element-ui基于cropper.js封装vue实现图片裁剪组件功能
-
cropper js基于vue的图片裁剪上传功能的实现代码
-
基于cropper.js封装vue实现在线图片裁剪组件功能
-
基于Vue的移动端图片裁剪组件功能
-
基于asp.net实现图片在线上传并在线裁剪功能
-
vue-cli结合Element-ui基于cropper.js封装vue实现图片裁剪组件功能
-
使用vue-cli结合Element-ui在cropper.js基础上封装vue来实现图片裁剪组件功能
-
cropper js基于vue的图片裁剪上传功能的实现代码
-
基于cropper.js封装vue实现在线图片裁剪组件功能