react怎样对图片进行裁剪

这次给大家带来react怎样对图片进行裁剪,react对图片进行裁剪的注意事项有哪些,下面就是实战案例,一起来看一下。

开始

写了一年多vue,感觉碰到了点瓶颈,学习下react找找感觉。刚好最近使用vue写了个基于cropperJS的图片裁剪的组件,便花费了几个晚上的功夫用react再写一遍。代码地址

项目是使用create-react-app来开发的,省去了很多webpack配置的功夫,支持eslint,自动刷新等功能,使用前npm install并npm start即可。推荐同样是新学习react的人也用用看。

项目写的比较简陋,自定义配置比较差,不过也是完成了裁剪图片的基本功能,希望可以帮助到初学react和想了解裁剪图片组件的朋友。

组件的结构是这样的。

   

@@##@@

this.resizeStart(event, 'top')}>

this.resizeStart(event, 'right')}>

this.resizeStart(event, 'bottom')}>

this.resizeStart(event, 'left')}>

this.resizeStart(event, 'right')}>

this.resizeStart(event, 'left')}>

登录后复制

ImageUploader & Cropper

ImageUploader主要做的就是上传图片,监听了input的change事件,并调用了父组件Cropper的的handleImgChange方法,该方法设置了绑定到img元素的imageValue,会使得img元素出发load事件。

 handleImgChange = e => {  let fileReader = new FileReader()  fileReader.readAsDataURL(e.target.files[0])  fileReader.onload = e => {   this.setState({...this.state, imageValue: e.target.result})  } }

登录后复制

load事件触发了Cropper的setSize方法,该方法可以设置了图片和裁剪选择框的初始位置和大小。目前裁剪选择框是默认设置是大小为图片的80%,中间显示。

 setSize = () => {  let img = this.refs.img  let widthNum = parseInt(this.props.width, 10)  let heightNum = parseInt(this.props.height, 10)  this.setState({   ...this.state,   naturalSize: {    width: img.naturalWidth,    height: img.naturalHeight   }  })  let imgStyle = img.style  imgStyle.height = 'auto'  imgStyle.width = 'auto'  let principalStyle = ReactDOM.findDOMNode(this.refs.selectArea).parentElement.style  const ratio = img.width / img.height  // 设置图片大小、位置  if (img.width > img.height) {   imgStyle.width = principalStyle.width = this.props.width   imgStyle.height = principalStyle.height = widthNum / ratio + 'px'   principalStyle.marginTop = (widthNum - parseInt(principalStyle.height, 10)) / 2 + 'px'   principalStyle.marginLeft = 0  } else {   imgStyle.height = principalStyle.height = this.props.height   imgStyle.width = principalStyle.width = heightNum * ratio + 'px'   principalStyle.marginLeft = (heightNum - parseInt(principalStyle.width, 10)) / 2 + 'px'   principalStyle.marginTop = 0  }  // 设置选择框样式  let selectAreaStyle = ReactDOM.findDOMNode(this.refs.selectArea).style  let principalHeight = parseInt(principalStyle.height, 10)  let principalWidth = parseInt(principalStyle.width, 10)  if (principalWidth > principalHeight) {   selectAreaStyle.top = principalHeight * 0.1 + 'px'   selectAreaStyle.width = selectAreaStyle.height = principalHeight * 0.8 + 'px'   selectAreaStyle.left = (principalWidth - parseInt(selectAreaStyle.width, 10)) / 2 + 'px'  } else {   selectAreaStyle.left = principalWidth * 0.1 + 'px'   selectAreaStyle.width = selectAreaStyle.height = principalWidth * 0.8 + 'px'   selectAreaStyle.top = (principalHeight - parseInt(selectAreaStyle.height, 10)) / 2 + 'px'  } }

登录后复制

Cropper上还有一个getCropData方法,方法会打印并返回裁剪参数,

 getCropData = e => {  e.preventDefault()  let SelectArea = ReactDOM.findDOMNode(this.refs.selectArea).style  let a = {   width: parseInt(SelectArea.width, 10),   height: parseInt(SelectArea.height, 10),   left: parseInt(SelectArea.left, 10),   top: parseInt(SelectArea.top, 10)  }  a.radio = this.state.naturalSize.width / a.width  console.log(a)  return a }

登录后复制

SelectArea

重新放一遍selectArea的结构。要注意,.top-resize的cursor属性是 n-resize,而和left,right,bottom对应的分别是w-resize,e-resize,s-resize

   

this.resizeStart(event, 'top')}>

this.resizeStart(event, 'right')}>

this.resizeStart(event, 'bottom')}>

this.resizeStart(event, 'left')}>

this.resizeStart(event, 'right')}>

this.resizeStart(event, 'left')}>

登录后复制

selectArea的state值设为这样,selectArea保存拖拽选择框时的参数,resizeArea保存裁剪选择框时的参数,container为.image-principal元素,el为触发事件时的event.target。

  this.state = {   selectArea: null,   el: null,   container: null,   resizeArea: null  }

登录后复制

拖拽选择框

在.select-area按下鼠标,触发mouseDown事件,调用dragStart方法。

使用method = e => {}的形式可以避免在jsx中使用this.method.bind(this)

在这个方法中,首先保存按下鼠标时的鼠标位置,裁剪框与图片的相对距离和裁剪框的最大位移距离,接着添加事件监听

 dragStart = e => {  const el = e.target  const container = this.state.container  let selectArea = {   posLeft: e.clientX,   posTop: e.clientY,   left: e.clientX - el.offsetLeft,   top: e.clientY - el.offsetTop,   maxMoveX: container.offsetWidth - el.offsetWidth,   maxMoveY: container.offsetHeight - el.offsetHeight,  }  this.setState({ ...this.state, selectArea, el})  document.addEventListener('mousemove', this.moveBind, false)  document.addEventListener('mouseup', this.stopBind, false) }

登录后复制

moveBind和stopBind来自于

 this.moveBind = this.move.bind(this) this.stopBind = this.stop.bind(this)

登录后复制

move方法,在鼠标移动中根据记录新的鼠标位置来计算新的相对位置newPosLeft和newPosTop,并控制该值在合理范围内

 move(e) {  if (!this.state || !this.state.el || !this.state.selectArea) {   return  }  let selectArea = this.state.selectArea  let newPosLeft = e.clientX- selectArea.left  let newPosTop = e.clientY - selectArea.top  // 控制移动范围  if (newPosLeft  selectArea.maxMoveX) {   newPosLeft = selectArea.maxMoveX  }  if (newPosTop  selectArea.maxMoveY) {   newPosTop = selectArea.maxMoveY  }  let elStyle = this.state.el.style  elStyle.left = newPosLeft + 'px'  elStyle.top = newPosTop + 'px' }

登录后复制

stop方法,移除事件监听,清除state,避免方法错误调用

 stop() {  document.removeEventListener('mousemove', this.moveBind , false)  document.removeEventListener('mousemove', this.resizeBind , false)  document.removeEventListener('mouseup', this.stopBind, false)  this.setState({...this.state, el: null, resizeArea: null, selectArea: null}) }

登录后复制

裁剪选择框

跟拖拽一样,首先调用resizeStart方法,保存开始裁剪的鼠标位置,裁剪框的尺寸和位置,添加关于resizeBind和stopBind的事件监听,注意,由于react的事件机制特点,需要使用stopPropagation来禁止事件冒泡,事件监听的第三个参数使用false是无效的。

 resizeStart = (e, type) => {  e.stopPropagation()  const el = e.target.parentElement  let resizeArea = {   posLeft: e.clientX,   posTop: e.clientY,   width: el.offsetWidth,   height: el.offsetHeight,   left: parseInt(el.style.left, 10),   top: parseInt(el.style.top, 10)  }  this.setState({ ...this.state, resizeArea, el})  this.resizeBind = this.resize.bind(this, type)  document.addEventListener('mousemove', this.resizeBind, false)  document.addEventListener('mouseup', this.stopBind, false) }

登录后复制

裁剪的方法,将裁剪分为两种情况,一种是右侧,下侧和右下侧的拉伸。另一种是左侧,上侧和左上侧的拉伸。

第一种情况下,选择框的位置是不会变的,只有尺寸会变,处理起来相对简单。新的尺寸大小为原大小加上当前的鼠标的位置再减去开始拖拽处的鼠标的位置,如果宽度或者高度有一个超标了,则将尺寸设置为刚好到边界的大小。均为超标,设置为新的尺寸。

第二种情况下,选择框的位置和大小同时会变,要同时控制尺寸和位置不超出边界。

 resize(type, e) {  if (!this.state || !this.state.el || !this.state.resizeArea) {   return  }  let container = this.state.container  const containerHeight = container.offsetHeight  const containerWidth = container.offsetWidth  const containerLeft = parseInt(container.style.left || 0, 10)  const containerTop = parseInt(container.style.top || 0, 10)  let resizeArea = this.state.resizeArea  let el = this.state.el  let elStyle = el.style  if (type === 'right' || type === 'bottom') {   let length   if (type === 'right') {    length = resizeArea.width + e.clientX - resizeArea.posLeft   } else {    length = resizeArea.height + e.clientY - resizeArea.posTop   }   if (parseInt(el.style.left, 10) + length > containerWidth || parseInt(el.style.top, 10) + length > containerHeight) {    const w = containerWidth - parseInt(el.style.left, 10)    const h = containerHeight - parseInt(el.style.top, 10)    elStyle.width = elStyle.height = Math.min(w, h) + 'px'   } else {    elStyle.width = length + 'px'    elStyle.height = length + 'px'   }  } else {   let posChange   let newPosLeft   let newPosTop   if (type === 'left') {    posChange = resizeArea.posLeft - e.clientX   } else {    posChange = resizeArea.posTop - e.clientY   }   newPosLeft = resizeArea.left - posChange   // 防止过度缩小   if (newPosLeft > resizeArea.left + resizeArea.width) {    elStyle.left = resizeArea.left + resizeArea.width + 'px'    elStyle.top = resizeArea.top + resizeArea.height + 'px'    elStyle.width = elStyle.height = '2px'    return   }   newPosTop = resizeArea.top - posChange   // 到达边界   if (newPosLeft <= containerLeft || newPosTop < containerTop) {    // 让选择框到图片最左边    let newPosLeft2 = resizeArea.left -containerLeft    // 判断顶部会不会超出边界    if (newPosLeft2 < resizeArea.top) {     // 未超出边界     elStyle.top = resizeArea.top - newPosLeft2 + 'px'     elStyle.left = containerLeft + 'px'    } else {     // 让选择框到达图片顶部     elStyle.top = containerTop + 'px'     elStyle.left = resizeArea.left + containerTop - resizeArea.top + 'px'    }   } else {    if (newPosLeft < 0) {     elStyle.left = 0;     elStyle.width = Math.min(resizeArea.width + posChange - newPosLeft, containerWidth) + 'px'     elStyle.top = newPosTop - newPosLeft;     elStyle.height = Math.min(resizeArea.height + posChange - newPosLeft, containerHeight) + 'px'     return;    }    if (newPosTop < 0) {     elStyle.left = newPosLeft - newPosTop;     elStyle.width = Math.min(resizeArea.width + posChange - newPosTop, containerWidth) + 'px'     elStyle.top = 0;     elStyle.height = Math.min(resizeArea.height + posChange - newPosTop, containerHeight) + 'px'     return;    }    elStyle.left = newPosLeft + 'px'    elStyle.top = newPosTop + 'px'    elStyle.width = resizeArea.width + posChange + 'px'    elStyle.height = resizeArea.height + posChange + 'px'   }  } }

登录后复制

相信看了本文案例你已经掌握了方法,更多精彩请关注【创想鸟】其它相关文章!

推荐阅读:

如何使用vue隐藏div

如何使用vue隐藏div

react怎样对图片进行裁剪

以上就是react怎样对图片进行裁剪的详细内容,更多请关注【创想鸟】其它相关文章!

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

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

(0)
上一篇 2025年3月31日 23:11:16
下一篇 2025年3月31日 23:11:22

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

相关推荐

发表回复

登录后才能评论