详解vue项目中实现图片裁剪功能


Posted in Javascript onJune 07, 2019

演示地址

https://my729.github.io/picture-crop-demo/dist/#/

前言

  • vue版本:3.6.3 https://cli.vuejs.org/zh/
  • cropperjs: 1.5.1 https://github.com/fengyuanchen/cropperjs
  • elementUI https://element.eleme.io/#/zh-CN

使用 cropperjs插件 和 原生canvas 两种方式实现图片裁剪功能

使用cropperjs插件

安装cropperjs

yarn install cropperjs

初始化一个canvas元素,并在上面绘制图片

<canvas :id="data.src" ref="canvas"></canvas>
// 在canvas上绘制图片
drawImg () {
 this.$nextTick(() => {
 // 获取canvas节点
 let canvas = document.getElementById(this.data.src)
 if (canvas) {
 // 设置canvas的宽为canvas的父元素宽度,宽高比3:2
 let parentEle = canvas.parentElement
 canvas.width = parentEle.offsetWidth
 canvas.height = 2 * parentEle.offsetWidth / 3
 let ctx = canvas.getContext('2d')
 ctx.clearRect(0, 0, canvas.width, canvas.height)
 let img = new Image()
 img.crossOrigin = 'Anonymous'
 img.src = this.data.src
 img.onload = function () {
 ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
 }
 }
 })
}

如果遇到canvas跨域绘制图片报错,设置图片img.crossOrigin = 'Anonymous',并且服务器响应头设置Access-Control-Allow-Origin:*

创建cropperjs

// 引入
import Cropper from 'cropperjs'

// 显示裁剪框
initCropper () {
 let cropper = new Cropper(this.$refs.canvas, {
 checkCrossOrigin: true,
 viewMode: 2,
 aspectRatio: 3 / 2
 })
}

更多方法和属性,参考官网: https://github.com/fengyuanchen/cropperjs

具体实现,可以查看源码的cropper.vue 或 cropper.one.vue组件:

cropper.vue组件:https://github.com/MY729/picture-crop-demo/blob/master/src/components/cropper.vue
cropper.one.vue组件:https://github.com/MY729/picture-crop-demo/blob/master/src/components/cropper.one.vue

使用canvas实现图片裁剪

支持鼠标绘制裁剪框,并移动裁剪框

思路:

  • 在canvas上绘制图片为背景
  • 监听鼠标点击、移动、松开事件

canvas的isPointInPath()方法: 如果给定的点的坐标位于路径之内的话(包括路径的边),否则返回 false

具体实现可查看源码cropper.canvas.vue组件: https://github.com/MY729/picture-crop-demo/blob/master/src/components/cropper.canvas.vue

cropImg () {
 let canvas = document.getElementById(this.data.img_url)
 let ctx = canvas.getContext('2d')
 let img = new Image()
 img.onload = function () {
 ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
 }
 img.src = this.data.src
 let drag = false // 是否拖动矩形
 let flag = false // 是否绘制矩形
 let rectWidth = 0 // 绘制矩形的宽
 let rectHeight = 0 // 绘制矩形的高
 let clickX = 0 // 矩形开始绘制X坐标
 let clickY = 0 // 矩形开始绘制Y坐标
 let dragX = 0 // 当要拖动矩形点击时X坐标
 let dragY = 0 // 当要拖动矩形点击时Y坐标
 let newRectX = 0 // 拖动变化后矩形开始绘制的X坐标
 let newRectY = 0 // 拖动变化后矩形开始绘制的Y坐标
 // 鼠标按下
 canvas.onmousedown = e => {
 // 每次点击前如果有绘制好的矩形框,通过路径绘制出来,用于下面的判断
 ctx.beginPath()
 ctx.setLineDash([6, 6])
 ctx.moveTo(newRectX, newRectY)
 ctx.lineTo(newRectX + rectWidth, newRectY)
 ctx.lineTo(newRectX + rectWidth, newRectY + rectHeight)
 ctx.lineTo(newRectX, newRectY + rectHeight)
 ctx.lineTo(newRectX, newRectY)
 ctx.strokeStyle = 'green'
 ctx.stroke()
 // 每次点击,通过判断鼠标点击的点在矩形框内还是外,来决定重新绘制还是移动矩形框
 if (ctx.isPointInPath(e.offsetX, e.offsetY)) {
 drag = true
 dragX = e.offsetX
 dragY = e.offsetY
 clickX = newRectX
 clickY = newRectY
 } else {
 ctx.clearRect(0, 0, canvas.width, canvas.height)
 ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
 flag = true
 clickX = e.offsetX
 clickY = e.offsetY
 newRectX = e.offsetX
 newRectY = e.offsetY
 }
 }
 // 鼠标抬起
 canvas.onmouseup = () => {
 if (flag) {
 flag = false
 this.sureCrop(clickX, clickY, rectWidth, rectHeight)
 }
 if (drag) {
 drag = false
 this.sureCrop(newRectX, newRectY, rectWidth, rectHeight)
 }
 }
 // 鼠标移动
 canvas.onmousemove = (e) => {
 if (flag) {
 ctx.clearRect(0, 0, canvas.width, canvas.height)
 ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
 rectWidth = e.offsetX - clickX
 rectHeight = e.offsetY - clickY

 ctx.beginPath()
 ctx.strokeStyle = '#FF0000'
 ctx.strokeRect(clickX, clickY, rectWidth, rectHeight)
 ctx.closePath()
 }
 if (drag) {
 ctx.clearRect(0, 0, canvas.width, canvas.height)
 ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
 ctx.beginPath()
 newRectX = clickX + e.offsetX - dragX
 newRectY = clickY + e.offsetY - dragY
 ctx.strokeStyle = 'yellow'
 ctx.strokeRect(newRectX, newRectY, rectWidth, rectHeight)
 ctx.closePath()
 }
 }
},
// 拿到裁剪后的参数,可自行处理图片
sureCrop (x, y, width, height) {
 let canvas = document.getElementById(this.data.img_url + 'after')
 // 设置canvas的宽为canvas的父元素宽度,宽高比3:2
 let parentEle = canvas.parentElement
 canvas.width = parentEle.offsetWidth
 canvas.height = 2 * parentEle.offsetWidth / 3
 let ctx = canvas.getContext('2d')
 let img = new Image()
 img.src = this.data.src
 img.onload = function () {
 ctx.beginPath()
 ctx.moveTo(x, y)
 ctx.lineTo(x + width, y)
 ctx.lineTo(x + width, y + height)
 ctx.lineTo(x, y + height)
 ctx.clip()
 ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
 }
 ctx.stroke()
}

源码地址

https://github.com/MY729/picture-crop-demo

可以直接clone项目,本地运行查看代码和效果

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript下高性能字符串连接StringBuffer类
Aug 16 Javascript
Js 去掉字符串中的空格(实现代码)
Nov 19 Javascript
js面向对象之公有、私有、静态属性和方法详解
Apr 17 Javascript
jquery实现表单验证简单实例演示
Nov 23 Javascript
JavaScript转换与解析JSON方法实例详解
Nov 24 Javascript
js实现不重复导入的方法
Mar 02 Javascript
购物车前端开发(jQuery和bootstrap3)
Aug 27 Javascript
jQuery Validate让普通按钮触发表单验证的方法
Dec 15 Javascript
Vue异步组件使用详解
Apr 08 Javascript
详解webpack4多入口、多页面项目构建案例
May 25 Javascript
分享8个JavaScript库可更好地处理本地存储
Oct 12 Javascript
js仿淘宝放大镜效果
Dec 28 Javascript
sortable+element 实现表格行拖拽的方法示例
Jun 07 #Javascript
利用Vue-draggable组件实现Vue项目中表格内容的拖拽排序
Jun 07 #Javascript
Vue中实现权限控制的方法示例
Jun 07 #Javascript
vue 父组件中调用子组件函数的方法
Jun 06 #Javascript
通过seajs实现JavaScript的模块开发及按模块加载
Jun 06 #Javascript
小试小程序云开发(小结)
Jun 06 #Javascript
怎么使用javascript深度拷贝一个数组
Jun 06 #Javascript
You might like
PHP中基本符号及使用方法
2010/03/23 PHP
PHP编码规范的深入探讨
2013/06/06 PHP
php阻止页面后退的方法分享
2014/02/17 PHP
CodeIgniter中使用cookie的三种方式详解
2014/07/18 PHP
thinkphp数据查询和遍历数组实例
2014/11/28 PHP
php实现JWT(json web token)鉴权实例详解
2019/11/05 PHP
Jquery优化效率 提升性能解决方案
2010/09/06 Javascript
jQuery学习笔记之jQuery+CSS3的浏览器兼容性
2015/01/19 Javascript
JS实现FLASH幻灯片图片切换效果的方法
2015/03/04 Javascript
网页收藏夹显示ICO图标(代码少)
2015/08/04 Javascript
jquery实现可自动收缩的TAB网页选项卡代码
2015/09/06 Javascript
Node.js检测端口(port)是否被占用的简单示例
2016/09/29 Javascript
JS限制条件补全问题实例分析
2016/12/16 Javascript
快速实现JS图片懒加载(可视区域加载)示例代码
2017/01/04 Javascript
解决vue.js在编写过程中出现空格不规范报错的问题
2017/09/20 Javascript
AngularJS使用ng-repeat遍历二维数组元素的方法详解
2017/11/11 Javascript
vue 不使用select实现下拉框功能(推荐)
2018/05/17 Javascript
JavaScript设计模式之职责链模式应用示例
2018/08/07 Javascript
javascript触发模拟鼠标点击事件
2019/06/26 Javascript
java遇到微信小程序 &quot;支付验证签名失败&quot; 问题解决
2019/12/22 Javascript
vant 时间选择器--开始时间和结束时间实例
2020/11/04 Javascript
Python使用scrapy采集数据时为每个请求随机分配user-agent的方法
2015/04/08 Python
详解python3百度指数抓取实例
2016/12/12 Python
PyTorch快速搭建神经网络及其保存提取方法详解
2018/04/28 Python
解决Matplotlib图表不能在Pycharm中显示的问题
2018/05/24 Python
Python使用itchat模块实现简单的微信控制电脑功能示例
2019/08/26 Python
使用python将excel数据导入数据库过程详解
2019/08/27 Python
python词云库wordCloud使用方法详解(解决中文乱码)
2020/02/17 Python
Python文件读写w+和r+区别解析
2020/03/26 Python
本科生详细的自我评价
2013/09/19 职场文书
商务日语毕业生自荐信范文
2013/11/14 职场文书
大学老师推荐信
2014/02/25 职场文书
元旦晚会感言
2014/03/12 职场文书
职业道德模范事迹材料
2014/08/24 职场文书
庆六一文艺汇演活动方案
2014/08/26 职场文书
死亡诗社观后感
2015/06/05 职场文书