ホームページ ウェブフロントエンド jsチュートリアル React で画像をトリミングする方法

React で画像をトリミングする方法

Jun 07, 2018 pm 01:53 PM
react 画像のトリミング

今回はReactで画像をトリミングする方法と、Reactで画像をトリミングする際の注意点を紹介します。実際のケースを見てみましょう。

を始めて 1 年以上 Vue を書いてきましたが、ボトルネックに達したと感じています。その感覚を知るために React を勉強します。たまたま最近、Vue を使用して CropperJS に基づいた画像トリミング コンポーネントを作成したため、数晩かけて React を使用して再度作成しました。コードアドレス

このプロジェクトは create-react-app を使用して開発されており、使用前に eslint、自動更新、その他の機能をサポートしています。初めて反応する人も試してみることをおすすめします。

このプロジェクトは比較的簡単に作成でき、カスタム構成も比較的貧弱ですが、画像をトリミングするという基本的な機能も完成しているので、初めて反応し、画像のトリミング コンポーネントを理解したいと考えている友人に役立つことを願っています。 。

コンポーネントの構造はこんな感じです。

<!--Cropper-->
   <p>
   <ImageUploader handleImgChange={this.handleImgChange} getCropData={this.getCropData}/>
    <p className="image-principal">
     <img src={this.state.imageValue} alt="" className="img" ref="img" onLoad={this.setSize}/>
     <SelectArea ref="selectArea"></SelectArea>
    </p>
   </p>
<!--ImageUploader   -->
   <form className="image-upload-form" method="post" encType="multipart/form-data" >
    <input type="file" name="inputOfFile" ref="imgInput" id="imgInput" onChange={this.props.handleImgChange}/>
    <button onClick={this.props.getCropData}>获取裁剪参数</button>
   </form>
<!--SelectArea   -->
   <p className="select-area" onMouseDown={ this.dragStart} ref="selectArea" >
    <p className="top-resize" onMouseDown={ event => this.resizeStart(event, 'top')}></p>
    <p className="right-resize" onMouseDown={ event => this.resizeStart(event, 'right')}></p>
    <p className="bottom-resize" onMouseDown={ event => this.resizeStart(event, 'bottom')}></p>
    <p className="left-resize" onMouseDown={ event => this.resizeStart(event, 'left')}></p>
    <p className="right-bottom-resize" onMouseDown={ event => this.resizeStart(event, 'right')}></p>
    <p className="left-top-resize" onMouseDown={ event => this.resizeStart(event, 'left')}></p>
   </p>
ログイン後にコピー

ImageUploader & Cropper

ImageUploader が行う主な処理は、画像をアップロードし、入力の変更イベントをリッスンし、親コンポーネント Cropper の handleImgChange メソッドを呼び出して、img 要素にバインドされた imageValue を設定することです。これにより、img 要素がロード イベントをトリガーします。

 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 のカーソル属性は n-resize であり、left、right、bottom に対応するものはそれぞれ w-resize、e-resize、s-resize であることに注意してください

   <p className="select-area" onMouseDown={ this.dragStart} ref="selectArea" >
    <p className="top-resize" onMouseDown={ event => this.resizeStart(event, 'top')}></p>
    <p className="right-resize" onMouseDown={ event => this.resizeStart(event, 'right')}></p>
    <p className="bottom-resize" onMouseDown={ event => this.resizeStart(event, 'bottom')}></p>
    <p className="left-resize" onMouseDown={ event => this.resizeStart(event, 'left')}></p>
    <p className="right-bottom-resize" onMouseDown={ event => this.resizeStart(event, 'right')}></p>
    <p className="left-top-resize" onMouseDown={ event => this.resizeStart(event, 'left')}></p>
   </p>
ログイン後にコピー
の状態値selectArea はこれに設定され、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)
 }
ログイン後にコピー
move メソッドからイベント リスナー

 this.moveBind = this.move.bind(this)
 this.stopBind = this.stop.bind(this)
ログイン後にコピー
moveBind と stopBind を追加します。マウスの移動中に、新しい相対位置 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 <= 0) {
   newPosLeft = 0
  } else if (newPosLeft > selectArea.maxMoveX) {
   newPosLeft = selectArea.maxMoveX
  }
  if (newPosTop <= 0) {
   newPosTop = 0
  } else if (newPosTop > selectArea.maxMoveY) {
   newPosTop = selectArea.maxMoveY
  }
  let elStyle = this.state.el.style
  elStyle.left = newPosLeft + 'px'
  elStyle.top = newPosTop + 'px'
 }
ログイン後にコピー
メソッドを停止し、イベントリスナーを削除し、状態をクリアし、不正なメソッド呼び出しを回避します

 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 メソッドを呼び出します。react のイベント メカニズムの特性により、stopPropagation を使用する必要があることに注意してください。イベントバブリングを禁止するイベントリスナーの第3パラメータとして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)
 }
ログイン後にコピー
カットの方法は、右側、下側、右下側のストレッチの2つの状況に分かれています。もう一つは左側、上側、左上側のストレッチです。

最初のケースでは、選択ボックスの位置は変更されず、サイズのみが変更され、処理は比較的簡単です。新しいサイズは、元のサイズに現在のマウス位置を加えたものから、ドラッグ開始時のマウス位置を引いたものになります。幅または高さのいずれかが標準を超える場合、そのサイズは境界に達するギリギリのサイズに設定されます。すべて基準を超えており、新しいサイズに設定されています。

2番目のケースでは、選択ボックスの位置とサイズが同時に変更され、境界を超えないようにサイズと位置を同時に制御する必要があります。

 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'
   }
  }
 }
ログイン後にコピー
この記事の事例を読んだ後は、この方法を習得したと思います。さらに興味深い情報については、php 中国語 Web サイトの他の関連記事に注目してください。

推奨読書:

vueを使ってdivを非表示にする方法


vuexの状態オブジェクトの使い方のまとめ

以上がReact で画像をトリミングする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

React と WebSocket を使用してリアルタイム チャット アプリを構築する方法 React と WebSocket を使用してリアルタイム チャット アプリを構築する方法 Sep 26, 2023 pm 07:46 PM

React と WebSocket を使用してリアルタイム チャット アプリケーションを構築する方法 はじめに: インターネットの急速な発展に伴い、リアルタイム コミュニケーションがますます注目を集めています。ライブチャット アプリは、現代の社会生活や仕事生活に不可欠な部分になっています。この記事では、React と WebSocket を使用して簡単なリアルタイム チャット アプリケーションを構築する方法と、具体的なコード例を紹介します。 1. 技術的な準備 リアルタイム チャット アプリケーションの構築を開始する前に、次のテクノロジとツールを準備する必要があります。 React: 構築用の 1 つ

React フロントエンドとバックエンドの分離ガイド: フロントエンドとバックエンドの分離と独立したデプロイメントを実現する方法 React フロントエンドとバックエンドの分離ガイド: フロントエンドとバックエンドの分離と独立したデプロイメントを実現する方法 Sep 28, 2023 am 10:48 AM

React フロントエンドとバックエンドの分離ガイド: フロントエンドとバックエンドの分離と独立したデプロイメントを実現する方法、特定のコード例が必要です 今日の Web 開発環境では、フロントエンドとバックエンドの分離がトレンドになっています。フロントエンド コードとバックエンド コードを分離することで、開発作業がより柔軟かつ効率的になり、チームのコラボレーションが促進されます。この記事では、React を使用してフロントエンドとバックエンドの分離を実現し、それによって分離と独立したデプロイの目標を達成する方法を紹介します。まず、フロントエンドとバックエンドの分離とは何かを理解する必要があります。従来の Web 開発モデルでは、フロントエンドとバックエンドが結合されています。

React と Flask を使用してシンプルで使いやすい Web アプリケーションを構築する方法 React と Flask を使用してシンプルで使いやすい Web アプリケーションを構築する方法 Sep 27, 2023 am 11:09 AM

React と Flask を使用してシンプルで使いやすい Web アプリケーションを構築する方法 はじめに: インターネットの発展に伴い、Web アプリケーションのニーズはますます多様化および複雑化しています。使いやすさとパフォーマンスに対するユーザーの要件を満たすために、最新のテクノロジー スタックを使用してネットワーク アプリケーションを構築することがますます重要になっています。 React と Flask は、フロントエンドおよびバックエンド開発用の 2 つの非常に人気のあるフレームワークであり、うまく連携してシンプルで使いやすい Web アプリケーションを構築します。この記事では、React と Flask を活用する方法について詳しく説明します。

React と RabbitMQ を使用して信頼性の高いメッセージング アプリを構築する方法 React と RabbitMQ を使用して信頼性の高いメッセージング アプリを構築する方法 Sep 28, 2023 pm 08:24 PM

React と RabbitMQ を使用して信頼性の高いメッセージング アプリケーションを構築する方法 はじめに: 最新のアプリケーションは、リアルタイム更新やデータ同期などの機能を実現するために、信頼性の高いメッセージングをサポートする必要があります。 React はユーザー インターフェイスを構築するための人気のある JavaScript ライブラリであり、RabbitMQ は信頼性の高いメッセージング ミドルウェアです。この記事では、React と RabbitMQ を組み合わせて信頼性の高いメッセージング アプリケーションを構築する方法を紹介し、具体的なコード例を示します。 RabbitMQ の概要:

React と Google BigQuery を使用して高速データ分析アプリケーションを構築する方法 React と Google BigQuery を使用して高速データ分析アプリケーションを構築する方法 Sep 26, 2023 pm 06:12 PM

React と Google BigQuery を使用して高速データ分析アプリケーションを構築する方法 はじめに: 今日の情報爆発の時代において、データ分析はさまざまな業界で不可欠なリンクとなっています。中でも、高速かつ効率的なデータ分析アプリケーションを構築することは、多くの企業や個人が追求する目標となっています。この記事では、React と Google BigQuery を使用して高速データ分析アプリケーションを構築する方法を紹介し、詳細なコード例を示します。 1. 概要 React はビルドするためのツールです

React コード デバッグ ガイド: フロントエンドのバグをすばやく見つけて解決する方法 React コード デバッグ ガイド: フロントエンドのバグをすばやく見つけて解決する方法 Sep 26, 2023 pm 02:25 PM

React コード デバッグ ガイド: フロントエンドのバグをすばやく見つけて解決する方法 はじめに: React アプリケーションを開発するとき、アプリケーションをクラッシュさせたり、不正な動作を引き起こしたりする可能性のあるさまざまなバグに遭遇することがよくあります。したがって、デバッグ スキルを習得することは、すべての React 開発者にとって不可欠な能力です。この記事では、フロントエンドのバグを見つけて解決するための実践的なテクニックをいくつか紹介し、読者が React アプリケーションのバグをすばやく見つけて解決できるようにする具体的なコード例を示します。 1. デバッグツールの選択: In Re

React Router ユーザーガイド: フロントエンドルーティング制御の実装方法 React Router ユーザーガイド: フロントエンドルーティング制御の実装方法 Sep 29, 2023 pm 05:45 PM

ReactRouter ユーザーガイド: フロントエンドルーティング制御の実装方法 シングルページアプリケーションの人気に伴い、フロントエンドルーティングは無視できない重要な部分になりました。 React エコシステムで最も人気のあるルーティング ライブラリとして、ReactRouter は豊富な機能と使いやすい API を提供し、フロントエンド ルーティングの実装を非常にシンプルかつ柔軟にします。この記事では、ReactRouter の使用方法と具体的なコード例を紹介します。 ReactRouter を最初にインストールするには、次のものが必要です

React レスポンシブ デザイン ガイド: アダプティブ フロントエンド レイアウト効果を実現する方法 React レスポンシブ デザイン ガイド: アダプティブ フロントエンド レイアウト効果を実現する方法 Sep 26, 2023 am 11:34 AM

React レスポンシブ デザイン ガイド: アダプティブ フロントエンド レイアウト効果を実現する方法 モバイル デバイスの人気と、マルチスクリーン エクスペリエンスに対するユーザーの需要の高まりに伴い、レスポンシブ デザインは最新のフロントエンド開発における重要な考慮事項の 1 つとなっています。 React は、現在最も人気のあるフロントエンド フレームワークの 1 つであり、開発者がアダプティブ レイアウト効果を実現するのに役立つ豊富なツールとコンポーネントを提供します。この記事では、React を使用してレスポンシブ デザインを実装するためのガイドラインとヒントをいくつか紹介し、参考として具体的なコード例を示します。 Reactを使用したファイル

See all articles