返回顶部
首页 > 资讯 > 前端开发 > html >基于Vue如何实现移动端图片裁剪组件功能
  • 197
分享到

基于Vue如何实现移动端图片裁剪组件功能

2024-04-02 19:04:59 197人浏览 独家记忆
摘要

小编给大家分享一下基于Vue如何实现移动端图片裁剪组件功能,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!最近项目上要做一个车牌识别的功能。本来以为很简单,只需要将图片扔给后台就可以了,但是

小编给大家分享一下基于Vue如何实现移动端图片裁剪组件功能,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

最近项目上要做一个车牌识别的功能。本来以为很简单,只需要将图片扔给后台就可以了,但是经测试后识别率只有20-40%。因此产品建议拍摄图片后,可以对图片进行拖拽和缩放,然后裁剪车牌部分上传给后台来提高识别率。刚开始的话还是百度了一下看看有没有现成的组件,但是找来找去都没有找到一个合适的,还好这个功能不是很着急,因此自己周末就在家里研究一下。

  Demo地址:https://vivialex.GitHub.io/demo/imageClipper/index.html

  下载地址:Https://github.com/vivialex/vue-imageClipper

  因为移动端是用vue,所以就写成了一个vue组件,下面就说说自己的一些实现思路(本人技术有限,各位大神请体谅。另外展示的代码不一定是某个功能的完整代码),先看看效果: 

基于Vue如何实现移动端图片裁剪组件功能 基于Vue如何实现移动端图片裁剪组件功能  

  一、组件的初始化参数

  1、图片img(url或者base64 data-url)

  2、截图的宽clipperImgWidth

  3、截图的高clipperImgHeight

props: {
  img: String, //url或dataUrl
  clipperImgWidth: {
    type: Number,
    default: 500
  },
  clipperImgHeight: {
    type: Number,
    default: 200
  }
}

  二、布局

  在Z轴方向看主要是由4层组成。第1层是一个占满整个容器canvas(称cCanvas);第2层是一个有透明度的遮罩层;第3层是裁剪的区域(示例图中的白色方框),里面包含一个与裁剪区域大小相等的canvas(称pCanvas);第4层是一个透明层gesture-mask,用作绑定touchstart,touchmove,touchend事件。其中两个canvas都会加载同一张图片,只是起始坐标不一样。为什么需要两个canvas?因为想做出当手指离开屏幕时,裁剪区域外的部分表面会有一个遮罩层的效果,这样能突出裁剪区域的内容。

<div class="cut-container" ref="cut">
  <canvas ref="canvas"></canvas>
  <!-- 裁剪部分 -->
  <div class="cut-part">
    <div class="pCanvas-container">
      <canvas ref="pCanvas"></canvas>
    </div>
  </div>
  <!-- 底部操作栏 -->
  <div class="action-bar">
    <button class="btn-cancel" @click="_cancel">取消</button>
    <button class="btn-ok" @click="_cut">确认</button>
  </div>
  <!-- 背景遮罩 -->
  <div class="mask" :class="{opacity: maskShow}"></div>
  <!-- 手势操作层 -->
  <div class="gesture-mask" ref="gesture"></div>
</div>

  三、初始化canvas

  canvas绘制的图片在hdpi显示屏上会出现模糊,具体原因这里不作分析,可以参考下这里。我这里的做法是让canvas的width与height为其CSS width/height的devicePixelRatio倍,以及调用canvas api时所传入的参数都要乘以window.devicePixelRatio。最后还要记录一下两个canvas坐标原点的x, y差值(originXDiff与originYDiff)。如下

_ratio(size) {
  return parseInt(window.devicePixelRatio * size);
},
_initCanvas() {
  let $canvas = this.$refs.canvas,
    $pCanvas = this.$refs.pCanvas,
    clipperClientRect = this.$refs.clipper.getBoundinGClientRect(),
    clipperWidth = parseInt(this.clipperImgWidth / window.devicePixelRatio),
    clipperHeight = parseInt(this.clipperImgHeight / window.devicePixelRatio);

  this.ctx = $canvas.getContext('2d');
  this.pCtx = $pCanvas.getContext('2d');

  //判断clipperWidth与clipperHeight有没有超过容器值
  if (clipperWidth < 0 || clipperWidth > clipperClientRect.width) {
    clipperWidth = 250
  }

  if (clipperHeight < 0 || clipperHeight > clipperClientRect.height) {
    clipperHeight = 100
  }

  //因为canvas在手机上会被放大,因此里面的内容会模糊,这里根据手机的devicePixelRatio来放大canvas,然后再通过设置css来收缩,因此关于canvas的所有值或坐标都要乘以devicePixelRatio
  $canvas.style.width = clipperClientRect.width + 'px';
  $canvas.style.height = clipperClientRect.height + 'px';
  $canvas.width = this._ratio(clipperClientRect.width);
  $canvas.height = this._ratio(clipperClientRect.height);

  $pCanvas.style.width = clipperWidth + 'px';
  $pCanvas.style.height = clipperHeight + 'px';
  $pCanvas.width = this._ratio(clipperWidth);
  $pCanvas.height = this._ratio(clipperHeight);

  //计算两个canvas原点的x y差值
  let cClientRect = $canvas.getBoundingClientRect(),
    pClientRect = $pCanvas.getBoundingClientRect();

  this.originXDiff = pClientRect.left - cClientRect.left;
  this.originYDiff = pClientRect.top - cClientRect.top;
  this.cWidth = cClientRect.width;
  this.cHeight = cClientRect.height;
}

  四、加载图片

  加载图片比较简单,首先是创建一个Image对象并监听器onload事件(因为加载的图片有可能是跨域的,因此要设置其crossOrigin属性为Anonymous,然后服务器上要设置Access-Control-Allow-Origin响应头)。加载的图片如果宽高大于容器的宽高,要对其进行缩小处理。最后垂直水平居中显示()(这里注意的是要保存图片绘制前的宽高值,因为日后缩放图片是以该值为基础再乘以缩放倍率,这里取imgStartWidth,imgStartHeight)如下

_loadImg() {
  if (this.imgLoading || this.loadImgQueue.length === 0) {
    return;
  }
  let img = this.loadImgQueue.shift();
  if (!img) {
    return;
  }
  let $img = new Image(),
    onLoad = e => {
      $img.removeEventListener('load', onLoad, false);
      this.$img = $img;
      this.imgLoaded = true;
      this.imgLoading = false;
      this._initImg($img.width, $img.height);
      this.$emit('loadSuccess', e);
      this.$emit('loadComplete', e);
      this._loadImg();
    },
    onError = e => {
      $img.removeEventListener('error', onError, false);
      this.$img = $img = null;
      this.imgLoading = false;
      this.$emit('loadError', e);
      this.$emit('loadComplete', e);
      this._loadImg();
    };
  this.$emit('beforeLoad');
  this.imgLoading = true;
  this.imgLoaded = false;
  $img.src = this.img;
  $img.crossOrigin = 'Anonymous'; //因为canvas toDataUrl不能操作未经允许的跨域图片,这需要服务器设置Access-Control-Allow-Origin头
  $img.addEventListener('load', onLoad, false);
  $img.addEventListener('error', onError, false);
}
_initImg(w, h) {
  let eW = null,
    eH = null,
    maxW = this.cWidth,
    maxH = this.cHeight - this.actionBarHeight;
  //如果图片的宽高都少于容器的宽高,则不做处理
  if (w <= maxW && h <= maxH) {
    eW = w;
    eH = h;
  } else if (w > maxW && h <= maxH) {
    eW = maxW;
    eH = parseInt(h / w * maxW);
  } else if (w <= maxW && h > maxH) {
    eW = parseInt(w / h * maxH);
    eH = maxH;
  } else {
    //判断是横图还是竖图
    if (h > w) {
      eW = parseInt(w / h * maxH);
      eH = maxH;
    } else {
      eW = maxW;
      eH = parseInt(h / w * maxW);
    }
  }
  if (eW <= maxW && eH <= maxH) {
    //记录其初始化的宽高,日后的缩放功能以此值为基础
    this.imgStartWidth = eW;
    this.imgStartHeight = eH;
    this._drawImage((maxW - eW) / 2, (maxH - eH) / 2, eW, eH);
  } else {
    this._initImg(eW, eH);
  }
}

   五、绘制图片

  下面的_drawImage有四个参数,分别是图片对应cCanvas的x,y坐标以及图片目前的宽高w,h。函数首先会清空两个canvas的内容,方法是重新设置canvas的宽高。然后更新组件实例中对应的值,最后再调用两个canvas的drawImage去绘制图片。对于pCanvas来说,其绘制的图片坐标值为x,y减去对应的originXDiff与originYDiff(其实相当于切换坐标系显示而已,因此只需要减去两个坐标系原点的x,y差值即可)。看看代码

_drawImage(x, y, w, h) {
  this._clearCanvas();
  this.imgX = parseInt(x);
  this.imgY = parseInt(y);
  this.imgCurrentWidth = parseInt(w);
  this.imgCurrentHeight = parseInt(h);
  //更新canvas
  this.ctx.drawImage(this.$img, this._ratio(x), this._ratio(y), this._ratio(w), this._ratio(h));
  //更新pCanvas,只需要减去两个canvas坐标原点对应的差值即可
  this.pCtx.drawImage(this.$img, this._ratio(x - this.originXDiff), this._ratio(y - this.originYDiff), this._ratio(w), this._ratio(h));
},
_clearCanvas() {
  let $canvas = this.$refs.canvas,
    $pCanvas = this.$refs.pCanvas;
  $canvas.width = $canvas.width;
  $canvas.height = $canvas.height;
  $pCanvas.width = $pCanvas.width;
  $pCanvas.height = $pCanvas.height;
}

   六、移动图片

  移动图片实现非常简单,首先给gesture-mask绑定touchstart,touchmove,touchend事件,下面分别介绍这三个事件的内容

  首先定义四个变量scx, scy(手指的起始坐标),iX,iY(图片目前的坐标,相对于cCanvas)。

  1、touchstart

    方法很简单,就是获取touches[0]的pageX,pageY来更新scx与scy以及更新iX与iY

  2、touchmove

    获取touches[0]的pageX,声明变量f1x存放,移动后的x坐标等于iX + f1x - scx,y坐标同理,最后调用_drawImage来更新图片。

  看看代码吧

_initEvent() {
  let $gesture = this.$refs.gesture,
    scx = 0,
    scy = 0;
  let iX = this.imgX,
    iY = this.imgY;
  $gesture.addEventListener('touchstart', e => {
    if (!this.imgLoaded) {
      return;
    }
    let finger = e.touches[0];
      scx = finger.pageX;
      scy = finger.pageY;
      iX = this.imgX;
      iY = this.imgY;  
  }, false);
  $gesture.addEventListener('touchmove', e => {
    e.preventDefault();
    if (!this.imgLoaded) {
      return;
    }
    let f1x = e.touches[0].pageX,
      f1y = e.touches[0].pageY;
      this._drawImage(iX + f1x - scx, iY + f1y - scy, this.imgCurrentWidth, this.imgCurrentHeight);
  }, false);
}

   七、缩放图片(这里不作特别说明的坐标都是相对于cCanvas坐标系)

  绘制缩放后的图片无非需要4个参数,缩放后图片左上角的坐标以及宽高。求宽高相对好办,宽高等于imgStartWidth * 缩放比率与imgstartHeight * 缩放倍率(imgStartWidth ,imgstartHeight 上文第四节有提到)。接下来就是求缩放倍率的问题了,首先在touchstart事件上求取两手指间的距离d1;然后在touchmove事件上继续求取两手指间的距离d2,当前缩放倍率= 初始缩放倍率 + (d2-d1) / 步长(例如每60px算0.1),touchend事件上让初始缩放倍率=当前缩放倍率。

  至于如何求取缩放后图片左上角的坐标值,在草稿纸上画来画去,画了很久......终于有点眉目。首先要找到一个缩放中心(这里做法是取双指的中点坐标,但是这个坐标必须要位于图片上,如果不在图片上,则取图片上离该中点坐标最近的点),然后存在下面这个等式

  (缩放中心x坐标 - 缩放后图片左上角x坐标)/ 缩放后图片的宽度 = (缩放中心x坐标 - 缩放前图片左上角x坐标)/ 缩放前图片的宽度;(y坐标同理)

  接下来看看下面这个例子(在visio找了很久都没有画坐标系的功能,所以只能手工画了)

  基于Vue如何实现移动端图片裁剪组件功能

  绿色框是一张10*5的图片,蓝色框是宽高放大两倍后的图片20*10,根据上面的公式推算的x2 = sx - w2(sx - x1) / w1,y2 = sy - h3(sy - y1) / h2。

  坚持...继续看看代码吧

_initEvent() {
  let $gesture = this.$refs.gesture,
    cClientRect = this.$refs.canvas.getBoundingClientRect(),
    scx = 0, //对于单手操作是移动的起点坐标,对于缩放是图片距离两手指的中点最近的图标。
    scy = 0,
    fingers = {}; //记录当前有多少只手指在触控屏幕
  //one finger
  let iX = this.imgX,
    iY = this.imgY;
  //two finger
  let figuRedistance = 0,
    pinchScale = this.imgScale;
  $gesture.addEventListener('touchstart', e => {
    if (!this.imgLoaded) {
      return;
    }
    if (e.touches.length === 1) {
      let finger = e.touches[0];
      scx = finger.pageX;
      scy = finger.pageY;
      iX = this.imgX;
      iY = this.imgY;
      fingers[finger.identifier] = finger;
    } else if (e.touches.length === 2) {
      let finger1 = e.touches[0],
        finger2 = e.touches[1],
        f1x = finger1.pageX - cClientRect.left,
        f1y = finger1.pageY - cClientRect.top,
        f2x = finger2.pageX - cClientRect.left,
        f2y = finger2.pageY - cClientRect.top;
      scx = parseInt((f1x + f2x) / 2);
      scy = parseInt((f1y + f2y) / 2);
      figureDistance = this._pointDistance(f1x, f1y, f2x, f2y);
      fingers[finger1.identifier] = finger1;
      fingers[finger2.identifier] = finger2;
      //判断变换中点是否在图片中,如果不是则去离图片最近的点
      if (scx < this.imgX) {
        scx = this.imgX;
      }
      if (scx > this.imgX + this.imgCurrentWidth) {
        scx = this.imgX + this.imgCurrentHeight;
      }
      if (scy < this.imgY) {
        scy = this.imgY;
      }
      if (scy > this.imgY + this.imgCurrentHeight) {
        scy = this.imgY + this.imgCurrentHeight;
      }
    }
  }, false);
  $gesture.addEventListener('touchmove', e => {
    e.preventDefault();
    if (!this.imgLoaded) {
      return;
    }
    this.maskShowTimer && clearTimeout(this.maskShowTimer);
    this.maskShow = false;
    if (e.touches.length === 1) {
      let f1x = e.touches[0].pageX,
        f1y = e.touches[0].pageY;
      this._drawImage(iX + f1x - scx, iY + f1y - scy, this.imgCurrentWidth, this.imgCurrentHeight);
    } else if (e.touches.length === 2) {
      let finger1 = e.touches[0],
        finger2 = e.touches[1],
        f1x = finger1.pageX - cClientRect.left,
        f1y = finger1.pageY - cClientRect.top,
        f2x = finger2.pageX - cClientRect.left,
        f2y = finger2.pageY - cClientRect.top,
        newFigureDistance = this._pointDistance(f1x, f1y, f2x, f2y),
        scale = this.imgScale + parseFloat(((newFigureDistance - figureDistance) / this.imgScaleStep).toFixed(1));
      fingers[finger1.identifier] = finger1;
      fingers[finger2.identifier] = finger2;
      if (scale !== pinchScale) {
        //目前缩放的最小比例是1,最大是5
        if (scale < this.imgMinScale) {
          scale = this.imgMinScale;
        } else if (scale > this.imgMaxScale) {
          scale = this.imgMaxScale;
        }
        pinchScale = scale;
        this._scale(scx, scy, scale);
      }
    }
  }, false);
  $gesture.addEventListener('touchend', e => {
    if (!this.imgLoaded) {
      return;
    }
    this.imgScale = pinchScale;
    //从finger删除已经离开的手指
    let touches = Array.prototype.slice.call(e.changedTouches, 0);
    touches.forEach(item => {
      delete fingers[item.identifier];
    });
    //迭代fingers,如果存在finger则更新scx,scy,iX,iY,因为可能缩放后立即单指拖动
    let i,
      fingerArr = [];
    for(i in fingers) {
      if (fingers.hasOwnProperty(i)) {
        fingerArr.push(fingers[i]);
      }
    }
    if (fingerArr.length > 0) {
      scx = fingerArr[0].pageX;
      scy = fingerArr[0].pageY;
      iX = this.imgX;
      iY = this.imgY;
    } else {
      this.maskShowTimer = setTimeout(() => {
        this.maskShow = true;
      }, 300);
    }
    //做边界值检测
    let x = this.imgX,
      y = this.imgY,
      pClientRect = this.$refs.pCanvas.getBoundingClientRect();
    if (x > pClientRect.left + pClientRect.width) {
      x = pClientRect.left
    } else if (x + this.imgCurrentWidth < pClientRect.left) {
      x = pClientRect.left + pClientRect.width - this.imgCurrentWidth;
    }
    if (y > pClientRect.top + pClientRect.height) {
      y = pClientRect.top;
    } else if (y + this.imgCurrentHeight < pClientRect.top) {
      y = pClientRect.top + pClientRect.height - this.imgCurrentHeight;
    }
    if (this.imgX !== x || this.imgY !== y) {
      this._drawImage(x, y, this.imgCurrentWidth, this.imgCurrentHeight);
    }
  });
},
_scale(x, y, scale) {
  let newPicWidth = parseInt(this.imgStartWidth * scale),
    newPicHeight = parseInt(this.imgStartHeight * scale),
    newIX = parseInt(x - newPicWidth * (x - this.imgX) / this.imgCurrentWidth),
    newIY = parseInt(y - newPicHeight * (y - this.imgY) / this.imgCurrentHeight);
  this._drawImage(newIX, newIY, newPicWidth, newPicHeight);
},
_pointDistance(x1, y1, x2, y2) {
  return parseInt(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}

  说明一下fingers是干嘛的,是用来记录当前有多少只手指在屏幕上触摸。可能会出现这种情况,双指缩放后,其中一只手指移出显示屏,而另外一个手指在显示屏上移动。针对这种情况,要在touchend事件上根据e.changedTouches来移除fingers里已经离开显示屏的finger,如果此时fingers里只剩下一个finger,则更新scx,scy,iX,iY为移动图片做初始化准备。

  八、裁剪图片

  这里很简单,就调用pCanvas的toDataURL方法就可以了

_clipper() {
  let imgData = null;
  try {
    imgData = this.$refs.pCanvas.toDataURL();
  } catch (e) {
    console.error('请在response header加上Access-Control-Allow-Origin,否则canvas无法裁剪未经许可的跨域图片');
  }
  this.$emit('sure', imgData);
}

看完了这篇文章,相信你对“基于Vue如何实现移动端图片裁剪组件功能”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网html频道,感谢各位的阅读!

--结束END--

本文标题: 基于Vue如何实现移动端图片裁剪组件功能

本文链接: https://lsjlt.com/news/72203.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 基于Vue如何实现移动端图片裁剪组件功能
    小编给大家分享一下基于Vue如何实现移动端图片裁剪组件功能,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!最近项目上要做一个车牌识别的功能。本来以为很简单,只需要将图片扔给后台就可以了,但是...
    99+
    2024-04-02
  • 怎么使用Vue实现移动端图片裁剪组件功能
    本篇内容主要讲解“怎么使用Vue实现移动端图片裁剪组件功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用Vue实现移动端图片裁剪组件功能”吧!  一、组件的初始化参数  1、图片img(...
    99+
    2023-07-04
  • 基于JavaScript如何实现图片裁剪功能
    本篇内容介绍了“基于JavaScript如何实现图片裁剪功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、图片文件的上传和读取使用文件上...
    99+
    2023-07-05
  • 基于JavaScript实现图片裁剪功能
    目录一、图片文件的上传和读取二、图片展示和蒙层处理CSS clip-path三、裁剪框展示裁剪框的缩放点cursor 鼠标样式四、裁剪框移动事件五、裁剪框缩放操作六、完成裁剪功能dr...
    99+
    2023-02-21
    JavaScript实现图片裁剪JavaScript图片裁剪 JavaScript图片
  • 如何用Vue实现图片裁剪组件
    这篇文章主要介绍“如何用Vue实现图片裁剪组件”,在日常操作中,相信很多人在如何用Vue实现图片裁剪组件问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何用Vue实现图片裁剪组件”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-20
  • Vue实现简单基础的图片裁剪功能
    目录一、准备工作二、基本结构三、添加功能onMouseDownonMouseMoveonMouseUponMouseLeave四、总结近日,在写公司项目的时候接到一个需求:对已加载的...
    99+
    2024-04-02
  • Vue图片裁剪功能实现代码
    目录一、效果展示:1、表单的图片上传项:2、裁剪框页面二、代码部分1、首先安装Vue-Cropper,基于此组件的基础上开发的裁剪页面2、裁剪弹窗的组件编写:3、【图片上传表单项】组...
    99+
    2024-04-02
  • 基于Html5 canvas如何实现裁剪图片和马赛克功能
    这篇文章主要介绍了基于Html5 canvas如何实现裁剪图片和马赛克功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.核心功能  此组件功能包含:    图片裁剪(裁剪...
    99+
    2023-06-09
  • vue项目实现添加图片裁剪组件
    本文实例为大家分享了vue项目添加图片裁剪组件的具体代码,供大家参考,具体内容如下 功能如下图所示: 1、安装命令如下 npm i vue-cropper --save 2、调用组...
    99+
    2024-04-02
  • 基于RxPaparazzo实现图片裁剪、图片旋转、比例放大缩小功能
    前言:基于RxPaparazzo的图片裁剪,图片旋转、比例放大|缩小。效果: 开发环境:AndroidStudio2.2.1+gradle-2.14.1 涉及知识:Material Design(CardView+Coo...
    99+
    2023-05-31
    rxpaparazzo 图片裁剪 para
  • JavaScript如何实现小程序图片裁剪功能
    这篇文章主要介绍“JavaScript如何实现小程序图片裁剪功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JavaScript如何实现小程序图片裁剪功能”文章能帮助大家解决问题。图片上传与处理要...
    99+
    2023-07-05
  • Android如何实现裁剪照片功能
    这篇文章主要介绍Android如何实现裁剪照片功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!   从相册选择照片进行裁剪从相册选择照片并裁剪:private void cropFromGallery()...
    99+
    2023-06-29
  • Mint UI如何实现基于Vue.js移动端组件库
    这篇文章将为大家详细讲解有关Mint UI如何实现基于Vue.js移动端组件库,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Mint UI 包含丰富的 CSS 和 JS ...
    99+
    2024-04-02
  • vue项目ElementUI组件中el-upload组件与图片裁剪功能组件结合使用详解
    vue项目ElementUI组件中el-upload组件与裁剪功能组件结合使用,供大家参考,具体内容如下 如下图所示,点击上传组件,选择文件后,会立马弹出图片裁剪功能组件的页面 ...
    99+
    2024-04-02
  • js如何实现移动端图片压缩上传功能
    这篇文章给大家分享的是有关js如何实现移动端图片压缩上传功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。移动端图片压缩上传功能如何实现?做移动端开发的时候,form里面的fil...
    99+
    2024-04-02
  • 微信小程序如何实现图片选择区域裁剪功能
    这篇文章主要为大家展示了“微信小程序如何实现图片选择区域裁剪功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“微信小程序如何实现图片选择区域裁剪功能”这篇文章吧...
    99+
    2024-04-02
  • 如何实现一个基于canvas的移动端图片编辑器
    这篇文章给大家分享的是有关如何实现一个基于canvas的移动端图片编辑器的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。该插件是一款脱离jq的移动端图片编辑器。可以应用在移动端H5页面或者微信小程序中。插件实现的功...
    99+
    2023-06-09
  • javascript如何实现图片移动端
    这篇文章主要介绍“javascript如何实现图片移动端”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“javascript如何实现图片移动端”文章能帮助大家解决问题。首先,要实现图片的移动,我们需要...
    99+
    2023-07-06
  • 如何在ThinkPHP项目里添加图片尺寸动态裁剪功能
    这篇文章将为大家详细讲解有关如何在ThinkPHP项目里添加图片尺寸动态裁剪功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在 ThinkPHP 项目里添加图片尺寸动态裁剪功能ThinkPHP 图片动态...
    99+
    2023-06-14
  • Android基于widget组件实现物体移动/控件拖动功能示例
    本文实例讲述了Android基于widget组件实现物体移动/控件拖动功能。分享给大家供大家参考,具体如下: package com.sky; import android....
    99+
    2022-06-06
    示例 Android
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作