请选择 进入手机版 | 继续访问电脑版

好程序员-千锋教育旗下高端IT职业教育品牌

400-811-9990
我的账户
好程序员

专注高端IT职业培训

亲爱的猿猿,欢迎!

已有账号,请

如尚未注册?

[HTML5] 好程序员分享javascript实现自由编辑图片代码详解

[复制链接]
叶子老师 发表于 2019-7-19 16:03:48 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
  好程序员分享javascript实现自由编辑图片代码详解,当下我们项目中需要一个可自由编辑图片的功能,当图片可能出现需要频繁编辑,同时能满足发现裁剪不满意想要微调的时候,会发现如果我们处理图片按照平常的习惯,如裁剪后上传服务器或者转base64,都是不符合需求的。那么该怎么处理比较好呢?如何以尽量少的网络请求、少占用存储来解决应用场景呢?那么,便想到了只用纯数据来跟我们的功能打交道。
  先安利个裁图神器cropperjs,个人认为是个易上手,配置和api方法蛮齐全的一个组件库。
  项目内引入,一定不要漏了引用样式
  1
  2
  import Cropper from 'cropperjs';
  import 'cropperjs/dist/cropper.css';
  这里我们以react为例
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  this.state = {
  width: 640, //图片展示宽
  height: 360, //图片展示高
  imgWidth: 640, //图片实际宽
  imgHeight: 360, //图片实际高
  imgLeft: 0, //图片左偏移
  imgTop: 0, //图片上偏移
  editing: false //是否编辑中
  }
  //展示图片的基本dom结构,我们使用外div内img的形式,来跟数据结合控制裁剪图片的展示
  const { width, height, imgWidth, imgHeight, imgLeft, imgTop, editing } = this.state;
  const containerStyle = {
  width: `${width}px`,
  height: `${height}px`
  }
  const imgStyle = {
  width: `${imgWidth}px`,
  height: `${imgHeight}px`,
  left: `${imgLeft}px`,
  top: `${imgTop}px`
  }
  .img-container {
  overflow: hidden;
  position: relative;
  }
  .crop-img {
  position: absolute;
  left: 0;
  top: 0;
  }
  <div
  className="img-container"
  style={containerStyle}
  >
  <img
  className="crop-img"
  src={picture}
  style={imgStyle}
  alt="pic"
  ></img>
  </div>
  简单来说就是外层元素控制裁剪展示的宽高,同时根据项目需求的元素定位也挂在这,内部img挂载图片实际大小和偏移。
  cropperjs初始化后的元素,是会与初始化对象img处在同一dom层级,也就是说如果我们直接对展示img进行初始化的话,编辑区域展示将会受父元素,如图,放大图片时候会不方查看超出部分
  所以在这里,为了图片编辑的自由度,建议分开展示dom与用以初始化cropper对象的dom,在这里编辑区域为全屏幕为例,根据项目实际功能区域进行调整
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  .edit-container {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  }
  <div
  className="img-container"
  style={containerStyle}
  >
  <img
  className="crop-img"
  src={picture}
  style={imgStyle}
  alt="pic"
  ></img>
  </div>
  //cropper初始化
  this.myRef = React.createRef();
  this.myCropper = new Cropper(this.myRef.current, options);
  //options配置
  const options = {
  dragMode: 'move', //使裁剪时图片可拖动
  background: false, //因为我们现在是全屏可编辑,需要隐藏掉默认的背景
  }
  //当然还有许多常见的配置项,如编辑框尺寸比例等,大家可自行查看api
  //裁剪保存
  save() {
  const cropBoxData = this.myCropper.getCropBoxData(); //获取裁剪框数据
  const canvasData = this.myCropper.getCanvasData(); //获取图片数据
  this.setState({
  width: cropBoxData.width,
  height: cropBoxData.height,
  imgLeft: canvasData.left - cropBoxData.left,
  imgTop: canvasData.top - cropBoxData.top,
  imgWidth: canvasData.width,
  imgHeight: canvasData.height
  })
  }
  这样的话 我们就可以完全在自定义的全屏内编辑,保存效果如下,到这里我们就完成了第一部分功能,裁剪并保存数据和展示
  重点介绍下我们用到的两个api方法getCropBoxData和getCanvasData,getCanvasData是用来获取图片的实际数据的(当前的宽高,和相对于父元素可视区域的位移偏移量),getCropBoxData则是获取相对于图片区域的裁剪区相关数据。
  那么后续的需求接着来了,我们怎么做到二次编辑的时候,能还原效果呢,嗯,其实在前面我们记录裁图数据的时候,把相应的数据关系再计算一遍就好了,在初始化cropper的options中增加配置
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  const options = {
  dragMode: 'move',
  background: false,
  //控件初始化后重置相应配置
  ready: () => {
  const { width, height, imgWidth, imgHeight, imgLeft, imgTop } = this.state;
  //根据实际需要出现裁图功能进行定位,此处left和top仅为测试暂时默认值定义
  const left = 50;
  const top = 50;
  this.myCropper.setCanvasData({
  width: imgWidth,
  height: imgHeight,
  left: left,
  top: top
  });
  this.myCropper.setCropBoxData({
  left: left - imgLeft,
  top: top - imgTop,
  width: width,
  height: height
  })
  }
  }
  this.myCropper = new Cropper(this.myRef.current, options);
  这时候我们再点击裁图,就完美还原了,左边和上边的间隙就是setCanvasData的top和left,根据实际项目进行调整,setCropBoxData的left和top是相对于cropper-canvas的定位,才有了以上的计算形式。
  此时,基本功能到此结束,如果说是应用在h5编辑中,设计到scale缩放的话,相关的数据计算都要算上scale的缩放值哦,不然就会出现展示图片和编辑图片大小不对等的状况。同时还有许多功能就不做展示了,设置裁剪框比例,编辑缩放等,欢迎尝试。
  当然了,如果想要保存图片,也有相应的方法到处裁剪图片的数据
  this.myCropper.getCroppedCanvas().toDataURL('image/jpeg')
  最后,我们可以看到,在整个功能过程中,我们需要的只是裁剪的数据,读写快,也不需要进行额外的图片存储,减少文件服务器存储的开销与优化。
好程序员官网:http://www.goodprogrammer.org

精彩内容,一键分享给更多人!
回复

使用道具 举报

您需要登录后才可以回帖

本版积分规则

关注我们
好程序员
千锋好程序员

北京校区(总部):北京市海淀区宝盛北里西区28号中关村智诚科创大厦

深圳西部硅谷校区:深圳市宝安区宝安大道5010号深圳西部硅谷B座A区605-619

杭州龙驰智慧谷校区:浙江省杭州市下沙经济技术开发区元成路199号龙驰智慧谷B座7层

郑州校区:郑州市二七区航海中路60号海为科技园C区10层、12层

Copyright 2007-2019 北京千锋互联科技有限公司 .All Right

京ICP备12003911号-5 京公安网11010802011455号

请您保持通讯畅通1对1咨询马上开启