交流群:462197261站长百科站长论坛热门标签收藏本站北冥有鱼 互联网前沿资源第一站 助力全行业互联网+
点击这里给我发消息
  • 当前位置:
  • 详解vue项目中实现图片裁剪功能

    演示地址

    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项目,本地运行查看代码和效果

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

    您可能感兴趣的文章:

    • vue-image-crop基于Vue的移动端图片裁剪组件示例
    • Vue-cropper 图片裁剪的基本原理及思路讲解
    • 基于cropper.js封装vue实现在线图片裁剪组件功能
    • vue-cli结合Element-ui基于cropper.js封装vue实现图片裁剪组件功能
    • cropper js基于vue的图片裁剪上传功能的实现代码
    • 基于Vue的移动端图片裁剪组件功能
    • vue实现移动端图片裁剪上传功能

    广而告之:
    热门推荐:
    DEDE集成百度搜索谷歌搜索站内全站搜索站内按栏目搜索等功能的搜索栏

    DEDE可定制性非常强,我们接到一个项目,要求定制站点的搜索框,要求能有个选项,可以让访客点选使用百度搜索站内内容或者用谷歌搜索站点内容,或者直接搜索整站内容,或者点选按栏目搜索站内内容   全部代码如下:   <div class="search-bg&qu···

    如何让一个网站前端有气质可以吸引住用户

    web前端的网站气质是一种感觉,一种不需言语就可以把用户吸引住的感觉,那么,你认为网站的气质来自何处?如何培养呢? 1.网站战略:决定了网站的培养方向,错误的方向只会毁灭一个有潜力的天才。 2.网站灵魂/DNA:决定了网站最本质的东西,气质是网站灵魂无意识的外露···

    asp.net 动态表单之数据分页

    但是问题来了,不同科系的同学的科目是不一样的,那么我们在数据库设计的时候通常是把学生、某科成绩作为一条记录,那么这个时候我们就需要做一个行转列的逻辑处理了。 解决方法: 使用GridView来生成表单,这个实现起来会比较麻烦,如果要在列表里面显示链接就更不可能···

    PHP调用三种数据库的方法(2)

    开放数据库连接(ODBC)已成为一种与数据库进行通信的工业标准。PHP也提供了标准的接口,使得PHP能调用Access,SQL SERVER等数据库。其相关函数是: (1)integer odbc_connect(string dsn, string user, string password) 连接到一个ODBC数据库源名字上。 (2)integer ···

    iframe里面的元素触发父窗口元素事件的jquery代码

    例如父窗口定义了一个事件。 top: $(dom1).bind('topEvent', function(){}); 那么iframe里面的元素怎样触发父窗口dom1的事件呢?这样吗? $(dom1, parent.document).trigger('topEvent'); 看似正确,实则误导人。 因为父窗口的jquery对象与iframe里面的jquery对象实际为两个对···

    js操作滚动条事件实例

    本文实例讲述了js操作滚动条事件的方法。分享给大家供大家参考。具体分析如下: 之前一直很纳闷,如何监视滚动条的事件,今天终于有点明白了。 下边代码,是监听滚动条只要移动,下方的返回顶部的div显示与隐藏的代码 window.onscroll = function () { var t = document.do···

    URL Rewrite的设置方法

    URL Rewrite需要服务器的支持!在启用此设置之前,请确保服务器上已作出了正确的设置,设置方法请参看下边的“Apache下的设置方法”和“IIS下的设置方法”!Apache下的设置方法复制代码 代码如下:打开 Apache 的配置文件 httpd.conf 。  将#Lo···

    为WordPress添加文章字数统计的方法

    WordPress在后台编辑日志时编辑框左下角有一个字数统计,不过只显示在后台,能不能在前台也加上文章字数统计功能呢?研究了一下程序源文件,发现中文版WP后台的字数统计功能,是通过wp-content\languages目录的zh_CN-word-count.js实现的,就是不知道如何调用。网上搜了一下,···

    mysql利用参数sql

    前言 大家应该都知道,我们在mysql运维中出现过不少因为update/delete条件错误导致数据被误更新或者删除的case,为避免类似问题的发生,可以用sql_safe_updates参数来对update/delete做限制。这个参数设置为on后,可防止因程序bug或者DBA手工误操作导致的整个表被更新或者删除···