详解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中的float运算精度实例分析
Aug 21 Javascript
ajax中get和post的说明及使用与区别
Dec 23 Javascript
JS打开新窗口的2种方式
Apr 18 Javascript
jquery实现div拖拽宽度示例代码
Jul 31 Javascript
js中数组(Array)的排序(sort)注意事项说明
Jan 24 Javascript
jQuery选择器之基本选择器与层次选择器
Mar 03 Javascript
修改jquery中dialog的title属性方法(推荐)
Aug 26 Javascript
JavaScript禁用右键单击优缺点分析
Jan 20 Javascript
深入浅析Vue 中 ref 的使用
Apr 29 Javascript
Angular实现svg和png图片下载实现
May 05 Javascript
JS操作Fckeditor的一些常用方法(获取、插入等)
Feb 19 Javascript
JS实现简单打字测试
Jun 24 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数据库备份还原类分享
2014/03/20 PHP
THINKPHP项目开发中的日志记录实例分析
2014/12/01 PHP
php实现utf-8转unicode函数分享
2015/01/06 PHP
Kindeditor编辑器添加图片上传水印功能(php代码)
2017/08/03 PHP
JQuery 学习技巧总结
2010/05/21 Javascript
jQuery学习笔记之jQuery选择器的使用
2010/12/22 Javascript
将HTML格式的String转化为HTMLElement的实现方法
2014/08/07 Javascript
使用js画图之正弦曲线
2015/01/12 Javascript
jQuery Validate插件实现表单强大的验证功能
2015/12/18 Javascript
分析javascript中9 个常见错误阻碍你进步
2017/09/18 Javascript
webpack写jquery插件的环境配置
2017/12/21 jQuery
node.js利用socket.io实现多人在线匹配联机五子棋
2018/05/31 Javascript
React之PureComponent的使用作用
2018/07/10 Javascript
vue文件运行的方法教学
2019/02/12 Javascript
vue-router二级导航切换路由及高亮显示的实现方法
2019/07/10 Javascript
微信小程序new Date()方法失效问题解决方法
2019/07/29 Javascript
SSM+layUI 根据登录信息显示不同的页面方法
2019/09/20 Javascript
JavaScript前端实现压缩图片功能
2020/03/06 Javascript
基于原生js实现九宫格算法代码实例
2020/07/03 Javascript
布同 统计英文单词的个数的python代码
2011/03/13 Python
python相似模块用例
2016/03/04 Python
使用Python写CUDA程序的方法
2017/03/27 Python
Python编程之黑板上排列组合,你舍得解开吗
2017/10/30 Python
Python基础语言学习笔记总结(精华)
2017/11/14 Python
numpy实现合并多维矩阵、list的扩展方法
2018/05/08 Python
python smtplib模块自动收发邮件功能(一)
2018/05/22 Python
python设计tcp数据包协议类的例子
2019/07/23 Python
python3将变量写入SQL语句的实现方式
2020/03/02 Python
Python Selenium模块安装使用教程详解
2020/07/09 Python
乌克兰珠宝大卖场:Zlato.ua
2020/09/27 全球购物
Weblogic和WebSphere不同特点
2012/05/09 面试题
家长对老师的评语
2014/04/18 职场文书
文明家庭事迹材料
2014/12/20 职场文书
内乡县衙导游词
2015/02/05 职场文书
Tomcat配置访问日志和线程数
2022/05/06 Servers
MySQL的prepare使用以及遇到的bug
2022/05/11 MySQL