利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

这篇文章主要介绍了vue实现裁切图片同时实现放大、缩小、旋转功能,现在分享给大家,也给大家做个参考。

本篇文章主要介绍了vue实现裁切图片同时实现放大、缩小、旋转功能,分享给大家,具体如下:

实现效果:

裁切指定区域内的图片

旋转图片

立即学习“前端免费学习笔记(深入)”;

放大图片

输出bolb 格式数据 提供给 formData 对象

效果图

利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)

大概原理:

利用h5 FileReader 对象, 获取 “上传到浏览器的文件” ,文件形式 为base64形式, 把 base64 赋给canvas的上下文。

然后给canvas 元素上加入对(mousedown)监听事件。 当用户鼠标左键在canvas按下时:

挂载对 window 对象mousemove事件 —> 获取 鼠标移动x,y距离.从而操作 canvas里的图像的位置移动。

挂载对 window 对象mouseup 事件, 清除 mousemove事件的绑定。(同时该事件触发后会被删除)

剩下的 放大、缩小 、 旋转 是对 canvas 对象的操作/坐标体系的操作。具体api详见mdn canvas 文档

代码

dom.js

export const on = ({el, type, fn}) => {     if (typeof window) {       if (window.addEventListener) {         el.addEventListener(type, fn, false)      } else {         el.attachEvent(`on${type}`, fn)      }     }  }  export const off = ({el, type, fn}) => {    if (typeof window) {      if (window.addEventListener) {        el.removeEventListener(type, fn)      } else {        el.detachEvent(`on${type}`, fn)      }    }  }  export const once = ({el, type, fn}) => {    const hyFn = (event) => {      try {        fn(event)      }       finally {        off({el, type, fn: hyFn})      }    }    on({el, type, fn: hyFn})  }  // 最后一个  export const fbTwice = ({fn, time = 300}) => {    let [cTime, k] = [null, null]    // 获取当前时间    const getTime = () => new Date().getTime()    // 混合函数    const hyFn = () => {      const ags = argments      return () => {        clearTimeout(k)        k = cTime = null        fn(...ags)      }    }    return () => {      if (cTime == null) {        k = setTimeout(hyFn(...arguments), time)        cTime = getTime()      } else {        if ( getTime() - cTime  {      return item !== className    })    el.className =   classList.join(' ')  }  export const delay = ({fn, time}) => {    let oT = null    let k = null    return () => {      // 当前时间      let cT = new Date().getTime()      const fixFn = () => {        k = oT = null        fn()      }      if (k === null) {        oT = cT        k = setTimeout(fixFn, time)        return      }      if (cT - oT  {      fn()      this.off({type, fn: fixFn})    }    this.on({type, fn: fixFn})  }  Event.prototype.trigger = function (type){    if (this.typeList.hasOwnProperty(type)) {      this.typeList[type].forEach(fn => {        fn()      })    }  }

登录后复制

组件模板

  

                

      +            -      {{scale}}    

    

      upload      cancel    

    

      生成文件    

   import {on, off, once} from '../../utils/dom' export default { ctx: null, file: null, x: 0, // 点击canvas x 鼠标地址 y: 0,// 点击canvas y 鼠标地址 xV: 0, // 鼠标移动 x距离 yV: 0, // 鼠标移动 y距离 nX: 0, // 原始坐标点 图像 x nY: 0,// 原始坐标点 图像 y img: null, props: { src: { type: String, default: null }, clip: { type: Object, default () { return {width: '200px', height: '200px'} } } }, data () { return { isShow: false, base64: null, scale: 1.5, //放大比例 deg: 0 //旋转角度 } }, computed: { width () { const {clip} = this return parseFloat(clip.width.replace('px', '')) }, height () { const {clip} = this return parseFloat(clip.height.replace('px', '')) } }, mounted () { const {$options, $refs, width, height} = this // 初始化 canvas file nX nY Object.assign($options, { ctx: $refs.ctx.getContext('2d'), file: $refs.file, nX: -width / 2, nY: -height / 2 }) }, methods: { // 旋转操作 rotate () { const {$options, draw} = this this.deg = (this.deg + Math.PI /2)% (Math.PI * 2) draw($options.img, $options.nX + $options.xV, $options.nY + $options.yV, this.scale, this.deg) }, // 处理放大 handleScale (flag) { const {$options, draw, deg} = this flag && this.scale > 0.1 && (this.scale = this.scale - 0.1) !flag && this.scale { const img = createImage(e.target.result, (img) => { draw(img, nX, nY, scale, deg) }) file.value = null } reader.readAsDataURL(wFile) }, // 生成 图像 createImage (src, cb) { const img = new Image() this.$el.append(img) img.className = 'base64-hidden' img.onload = () => { cb(img) } img.src = src this.$options.img = img }, // 操作画布画图 draw (img, x = 0, y = 0, scale = 0.5,deg = Math.PI ) { const {ctx} = this.$options let {width, height} = this // 图片尺寸 let imgW = img.offsetWidth let imgH = img.offsetHeight ctx.save() ctx.clearRect( 0, 0, width, height) ctx.translate( width / 2, height / 2, img) ctx.rotate(deg) ctx.drawImage(img, x, y, imgW * scale, imgH * scale) ctx.restore() }, // ... 事件绑定 handleClip (e) { const {handleMove, $options, deg} = this if (!$options.img) { return } Object.assign(this.$options, { x: e.screenX, y: e.screenY }) on({ el: window, type: 'mousemove', fn: handleMove }) once({ el: window, type: 'mouseup', fn: (e) =>{ console.log('down') switch (deg) { case 0: { Object.assign($options, { nX: $options.nX + $options.xV, nY: $options.nY + $options.yV, xV: 0, yV: 0 }) break; } case Math.PI / 2: { Object.assign($options, { nX: $options.nY + $options.yV, nY: $options.nX - $options.xV, xV: 0, yV: 0 }) break; } case Math.PI: { Object.assign($options, { nX: $options.nX - $options.xV, nY: $options.nY - $options.yV, xV: 0, yV: 0 }) break; } default: { // $options.nY - $options.yV, $options.nX + $options.xV Object.assign($options, { nX: $options.nY - $options.yV, nY: $options.nX + $options.xV, xV: 0, yV: 0 }) } } off({ el: window, type: 'mousemove', fn: handleMove }) } }) }, // ... 处理鼠标移动 handleMove (e){ e.preventDefault() e.stopPropagation() const {$options, draw, scale, deg} = this Object.assign($options, { xV: e.screenX - $options.x, yV: e.screenY - $options.y }) switch (deg) { case 0: { draw($options.img, $options.nX + $options.xV, $options.nY + $options.yV, scale, deg) break; } case Math.PI / 2: { draw($options.img, $options.nY + $options.yV, $options.nX - $options.xV, scale, deg) break; } case Math.PI: { draw($options.img, $options.nX - $options.xV, $options.nY - $options.yV, scale, deg) break; } default: { draw($options.img, $options.nY - $options.yV, $options.nX + $options.xV, scale, deg) break; } } }, // 清除状态 clearState () { const {$options, width, height} = this if ($options.img) { this.$el.removeChild($options.img) Object.assign($options, { x: 0, y: 0, xV: 0, yV: 0, nX: -width / 2, nY: -height / 2, img: null, }) } }, // 输出文件 outFile () { const {$refs: {ctx}} = this console.log(ctx.toDataURL()) ctx.toBlob((blob) => {console.log(blob)}) } } } @component-namespace jc { @component clip-image{ position: relative; width: 100%; canvas { position: relative; width: 100%; height: 100%; cursor: pointer; box-shadow: 0 0 3px #333; } input { display: none; } .base64-hidden { position: absolute; top: 0; left: 0; display: block; width: 100%; height: auto; z-index: -999; opacity: 0; } .clip-scale-btn { position: relative; @utils-clearfix; margin-bottom: 5px; text-align: center; a { float: left; width: 20px; height: 20px; border-radius: 50%; color: #fff; background: #49a9ee; text-align: center; cursor: pointer; } &>.poor, &>.right-rotate { float: right; } &>span{ position: absolute; z-index: -9; top: 0; left: 0; display: block; position: relative; width: 100%; text-align: center; height: 20px; line-height: 20px; } } .upload-warp { @utils-clearfix; .upload-btn,.upload-cancel { float: left; display:inline-block; width: 60px; height: 25px; line-height: 25px; color: #fff; border-radius: 5px; background: #49a9ee; box-shadow: 0 0 0 #333; text-align: center; top: 0; left: 0; right: 0; bottom: 0; margin: auto; cursor: pointer; margin-top: 5px; } .upload-cancel{ background: gray; float: right; } } .to-send-file { margin-top: 5px; display: block; width: 50px; height: 25px; line-height: 25px; color: #fff; border-radius: 5px; background: #49a9ee; cursor: pointer; } }

登录后复制

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

利用vue如何实现图片滚动?

js实现操作二进制数据方法

利用vue2.0中swiper组件实现轮播(详细教程)

以上就是利用vue如何实现裁切图片同时实现放大、缩小、旋转功能(详细教程)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2751451.html

(0)
上一篇 2025年3月8日 05:52:00
下一篇 2025年2月19日 12:32:59

AD推荐 黄金广告位招租... 更多推荐

相关推荐

发表回复

登录后才能评论