基于cropper.js封装vue实现在线图片裁剪组件的功能

这篇文章主要介绍了基于cropper.js封装vue实现在线图片裁剪组件功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下

效果图如下所示,

基于cropper.js封装vue实现在线图片裁剪组件的功能

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两个文件

登录后复制

注意:必须先引入jquery文件,才能使用cropper.js插件

简单使用

构建截图所要用到的p容器

 ![](picture.jpg)

登录后复制

添加容器的样式,让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,从而达到能选择图片的功能

//模拟点击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 

非父子组件之间的通信问题

在之前的项目中,常用到父子组件之间的通信传参,一般用两种方法

在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选图截图插件完整代码

 

 

  

请点击按钮选择图片进行裁剪

  

  

  ![](!imgCropperData.imgUploadSrc ? '/images/thumbnail/thumbnail-img.jpg' : imgCropperData.imgUploadSrc)  

  

  ![](!imgCropperData.imgUploadSrc ? '/images/thumbnail/thumbnail-img.jpg' : imgCropperData.imgUploadSrc)  

  

  ![](!imgCropperData.imgUploadSrc ? '/images/thumbnail/thumbnail-img.jpg' : imgCropperData.imgUploadSrc)  

         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 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: '请重新裁剪图片进行上传!' }); } }); }, } } .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; }

登录后复制

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

关于iview table render集成switch开关的介绍

关于iview table render集成switch开关的介绍

以上就是基于cropper.js封装vue实现在线图片裁剪组件的功能的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2747736.html

(0)
上一篇 2025年3月8日 04:26:59
下一篇 2025年3月5日 15:02:08

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 分析关于Vue SSR 的 Cookies 问题

    本篇文章主要介绍了浅谈vue ssr 的 cookies 问题,内容挺不错的,现在分享给大家,也给大家做个参考。 一个网站一旦涉及到多用户, 就很难从 Cookies 中逃脱, Vue SSR 的 cookies 也真算是遇到的一个不小的问…

    编程技术 2025年3月8日
    200
  • vue 计算属性与方法跟侦听器区别的解析

    这篇文章主要介绍了详解vue 计算属性与方法跟侦听器区别(面试考点),内容挺不错的,现在分享给大家,也给大家做个参考。 计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如…

    2025年3月8日 编程技术
    200
  • Vue2.0 多 Tab切换组件的封装介绍

    本篇文章主要介绍了vue2.0 多 tab切换组件的封装实例,内容挺不错的,现在分享给大家,也给大家做个参考。 Vue2.0 多 Tab切换组件简单封装,满足自己简单的功能,可以直接拿去使用! 首先上效果图: 功能简单介绍: 1、支持tab…

    2025年3月8日
    200
  • Vue 去除路径中的#号的方法

    大家都知道vue-router有两种模式,hash模式和history模式,带#的则是hash模式。接下来给大家带来了vue 去除路径中的#号的解决方法,感兴趣的朋友一起看看吧 在开发过程中发现路径中带有/#/的标示,而且还去不掉,很丑陋。…

    2025年3月8日
    200
  • Vue组件通信实践的介绍

    本篇文章主要介绍了vue组件通信实践记录(推荐),内容挺不错的,现在分享给大家,也给大家做个参考。 组件通信 几乎所有的mvvm框架中都要涉及组件通信的功能(吐槽一下knockout,毕竟是鼻祖就先不说它了)。而且目前的前端形式来看,组件化…

    2025年3月8日
    200
  • VueJS组件之间通过props交互及验证的方式

    本篇文章主要介绍了vuejs组件之间通过props交互及验证的方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。 props 是父组件用来传递数据的一个自定义属性。父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用…

    2025年3月8日
    200
  • 如何解决Vue路由History mode模式中页面无法渲染

    这篇文章主要介绍了详解vue路由history mode模式中页面无法渲染的原因及解决,非常具有实用价值,需要的朋友可以参考下 Vue下路由History mode导致页面无法渲染的原因 用 Vue.js + vue-router 创建单页…

    2025年3月8日
    200
  • vue-cli构建项目反向代理配置的解析

    本篇文章主要介绍了详解vue-cli构建项目反向代理配置,内容挺不错的,现在分享给大家,也给大家做个参考。 本文介绍了vue-cli构建项目反向代理配置,分享给大家,具体如下: proxyTable: {//配置请求代理’/dlsys’:{…

    2025年3月8日
    200
  • 使用Vue自定义数字键盘组件的方法

    这篇文章主要介绍了关于使用vue自定义数字键盘组件的方法,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 最近做 Vue 开发,因为有不少页面涉及到金额输入,产品老是觉得用原生的 input 进行金额输入的话 体验很不好,于是…

    2025年3月8日
    200
  • vue单个组件实现无限层级多选菜单功能的介绍

    这篇文章主要介绍了vue单个组件实现无限层级多选菜单的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 wTree.vue  原理:每一个多选框都是一个节点,每个节点就是一个wTree组件,有父级(顶级level为0),有子级(底…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论