详解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 相关文章推荐
js/jQuery对象互转(快速操作dom元素)
Feb 04 Javascript
firefox下jquery ajax返回object XMLDocument处理方法
Jan 26 Javascript
js函数在frame中的相互调用详解
Mar 03 Javascript
JS实现左右拖动改变内容显示区域大小的方法
Oct 13 Javascript
微信小程序实现图片轮播及文件上传
Apr 07 Javascript
微信小程序如何获知用户运行小程序的场景教程
May 17 Javascript
Angular HMR(热模块替换)功能实现方法
Apr 04 Javascript
关于echarts在节点显示动态数据及添加提示文本所遇到的问题
Apr 20 Javascript
讲解vue-router之什么是嵌套路由
May 28 Javascript
babel7.x和webpack4.x配置vue项目的方法步骤
May 12 Javascript
vue使用swiper实现左右滑动切换图片
Oct 16 Javascript
深入详解JS函数的柯里化
Jun 09 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的类树(支持无限分类)
2006/10/09 PHP
一个PHP+MSSQL分页的例子
2006/10/09 PHP
Destoon实现多表查询示例
2014/08/21 PHP
ExtJS 2.2.1的grid控件在ie6中的显示问题
2009/05/04 Javascript
jquery trim() 功能源代码
2011/02/14 Javascript
js中escape对应的C#解码函数 UrlDecode
2012/12/16 Javascript
浅析Js中的单引号与双引号问题
2013/11/06 Javascript
JS中自定义定时器让它在某一时刻执行
2014/09/02 Javascript
node.js中的console.timeEnd方法使用说明
2014/12/09 Javascript
分享一个自己写的简单的javascript分页组件
2015/02/15 Javascript
JavaScript中的依赖注入详解
2015/03/18 Javascript
基于Javascript实现倒计时功能
2016/02/22 Javascript
使用JavaScript实现ajax的实例代码
2016/05/11 Javascript
js前端解决跨域问题的8种方案(最新最全)
2016/11/18 Javascript
JavaScript字符串对象
2017/01/14 Javascript
JS区分Object与Aarry的六种方法总结
2017/02/27 Javascript
angularjs实现柱状图动态加载的示例
2017/12/11 Javascript
JS实现数组简单去重及数组根据对象中的元素去重操作示例
2018/01/05 Javascript
讲解vue-router之什么是动态路由
2018/05/28 Javascript
基于vue实现移动端圆形旋钮插件效果
2018/11/28 Javascript
vue 项目接口管理的实现
2019/01/17 Javascript
Vue-CLI 3.X 部署项目至生产服务器的方法
2019/03/22 Javascript
bootstrap Table实现合并相同行
2019/07/19 Javascript
[03:06]2018年度CS GO最具人气解说-完美盛典
2018/12/16 DOTA
Python编程实现双击更新所有已安装python模块的方法
2017/06/05 Python
Python模拟登陆实现代码
2017/06/14 Python
利用python求解物理学中的双弹簧质能系统详解
2017/09/29 Python
win10 64bit下python NLTK安装教程
2018/09/19 Python
Python Pywavelet 小波阈值实例
2019/01/09 Python
python实现网站用户名密码自动登录功能
2019/08/09 Python
电台实习生求职信
2014/02/25 职场文书
生产部厂长助理职位说明书
2014/03/03 职场文书
护士上岗前培训自我鉴定
2014/04/20 职场文书
三月学雷锋月活动总结
2014/04/28 职场文书
学校政风行风自查自纠报告
2014/10/21 职场文书
小程序实现文字循环滚动动画
2021/06/14 Javascript