详解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实现带提示的星级评分效果完整实例
Oct 30 Javascript
AngularJS中如何使用$parse或$eval在运行时对Scope变量赋值
Jan 25 Javascript
vue2的todolist入门小项目的详细解析
May 11 Javascript
基于jQuery的左滑出现删除按钮的示例
Aug 29 jQuery
javascript中神奇的 Date对象小结
Oct 12 Javascript
VueJs 搭建Axios接口请求工具
Nov 20 Javascript
在vue项目创建的后初始化首次使用stylus安装方法分享
Jan 25 Javascript
用Axios Element实现全局的请求loading的方法
Mar 15 Javascript
微信小程序input框中加入小图标的实现方法
Jun 19 Javascript
vue axios基于常见业务场景的二次封装的实现
Sep 21 Javascript
Javascript查看大图功能代码实现
May 07 Javascript
如何基于jQuery实现五角星评分
Sep 02 jQuery
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
叫你如何修改Nginx与PHP的文件上传大小限制
2014/09/10 PHP
PHP实现加密的几种方式介绍
2015/02/22 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
2019/10/16 PHP
javascript 触发HTML元素绑定的函数
2010/09/11 Javascript
jquery基础教程之deferred对象使用方法
2014/01/22 Javascript
js停止冒泡和阻止浏览器默认行为的简单方法
2016/05/15 Javascript
原生js实现jquery函数animate()动画效果的简单实例
2016/08/21 Javascript
浅谈jquery高级方法描述与应用
2016/10/04 Javascript
View.post() 不靠谱的地方你知道多少
2017/08/29 Javascript
JavaScript模块详解
2017/12/18 Javascript
Vue中props的使用详解
2018/06/15 Javascript
微信小程序自定义音乐进度条的实例代码
2018/08/28 Javascript
微信小程序自定义可滑动日历界面
2018/12/28 Javascript
使用easyui从servlet传递json数据到前端页面的两种方法
2019/09/05 Javascript
js实现上传图片并显示图片名称
2019/12/18 Javascript
jquery实现轮播图特效
2020/04/12 jQuery
浅析JavaScript 函数防抖和节流
2020/07/13 Javascript
JS highcharts动态柱状图原理及实现
2020/10/16 Javascript
vue-cli中实现响应式布局的方法
2021/03/02 Vue.js
[01:32]寻找你心中的那团火 DOTA2 TI9火焰传递活动今日开启
2019/05/16 DOTA
用python实现的去除win下文本文件头部BOM的代码
2013/02/10 Python
pandas string转dataframe的方法
2018/04/11 Python
python pycurl验证basic和digest认证的方法
2018/05/02 Python
windows下python安装pip图文教程
2018/05/25 Python
用Pelican搭建一个极简静态博客系统过程解析
2019/08/22 Python
PyCharm 专业版安装图文教程
2020/02/20 Python
python在linux环境下安装skimage的示例代码
2020/10/14 Python
canvas三角函数模拟水波效果的示例代码
2018/07/03 HTML / CSS
英国演唱会订票网站:Ticket Selection
2018/03/27 全球购物
英国水族馆和池塘用品购物网站:Warehouse Aquatics
2019/08/29 全球购物
一套Delphi的笔试题一
2016/02/14 面试题
普通简短的个人自我评价
2014/02/15 职场文书
团支部建设方案
2014/05/02 职场文书
2014年最新党员对照检查材料汇总
2014/09/15 职场文书
乡镇2014法制宣传日活动总结
2014/11/01 职场文书
感恩老师主题班会
2015/08/12 职场文书