Heim > Artikel > Web-Frontend > So beschneiden Sie Bilder in React
Dieses Mal zeige ich Ihnen, wie Sie Bilder in React zuschneiden und welche Vorsichtsmaßnahmen beim Zuschneiden von Bildern in React gelten. Das Folgende ist ein praktischer Fall, schauen wir uns das an.
Starten
Ich schreibe Vue seit mehr als einem Jahr und ich habe das Gefühl, dass ich auf einen Engpass gestoßen bin, um das Gefühl herauszufinden. Ich habe erst vor Kurzem mit Vue eine auf CropperJS basierende Komponente zum Zuschneiden von Bildern geschrieben, also habe ich ein paar Nächte damit verbracht, sie noch einmal mit React zu schreiben. Das Codeadressen-
-Projekt wird mit der Create-React-App entwickelt, was viel Aufwand bei der Webpack-Konfiguration spart. Es unterstützt nur npm install und npm start vor der Verwendung. Es wird empfohlen, dass auch Leute, die noch keine Erfahrung mit der Reaktion haben, es ausprobieren.
Das Projekt ist relativ einfach zu schreiben und die benutzerdefinierte Konfiguration ist relativ schlecht. Ich hoffe jedoch, dass es Freunden, die neu sind, helfen kann, darauf zu reagieren Bildkomponente zuschneiden.
Die Struktur der Komponente ist wie folgt.
<!--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
Die Hauptaufgabe von ImageUploader besteht darin, Bilder hochzuladen, das Änderungsereignis der Eingabe abzuhören und die Methode handleImgChange der übergeordneten Komponente aufzurufen Cropper. Das Festlegen des an das img-Element gebundenen imageValue führt dazu, dass das img-Element das Ladeereignis auslöst. Das
handleImgChange = e => { let fileReader = new FileReader() fileReader.readAsDataURL(e.target.files[0]) fileReader.onload = e => { this.setState({...this.state, imageValue: e.target.result}) } }
load-Ereignis löst die setSize-Methode von Cropper aus, die die Anfangsposition und -größe des Bild- und Zuschneideauswahlfelds festlegt. Derzeit ist die Standardeinstellung des Zuschneideauswahlfelds so, dass die Größe 80 % des Bildes beträgt und in der Mitte angezeigt wird.
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' } }
Es gibt auch eine getCropData-Methode auf Cropper, die die Zuschneideparameter druckt und zurückgibt,
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
Die Struktur von selectArea wiedergeben . Es ist zu beachten, dass das Cursor-Attribut von .top-resize n-resize ist und die entsprechenden Attribute für links, rechts und unten w-resize, e-resize und s-resize sind
<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>
Die Der Statuswert von selectArea ist auf festgelegt. Auf diese Weise speichert selectArea die Parameter beim Ziehen des Auswahlfelds, resizeArea speichert die Parameter beim Zuschneiden des Auswahlfelds, Container ist das .image-principal-Element und el ist das event.target, wenn das Ereignis auftritt ausgelöst wird.
this.state = { selectArea: null, el: null, container: null, resizeArea: null }
Ziehen Sie das Auswahlfeld
Drücken Sie die Maus im .select-area, lösen Sie das MouseDown-Ereignis aus und rufen Sie die DragStart-Methode auf.
Durch die Verwendung von method = e => {} kann die Verwendung von this.method.bind(this) in jsx vermieden werden.
Speichern Sie bei dieser Methode zunächst die Position der Maus, wenn die Maus gedrückt wird relativer Abstand zwischen dem Zuschneiderahmen und dem Bild und der maximale Verschiebungsabstand des Zuschneiderahmens, und fügen Sie dann die Ereignis-Listener
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 und stopBind hinzu, die von der
this.moveBind = this.move.bind(this) this.stopBind = this.stop.bind(this)
move-Methode stammen, und zeichnen Sie neue auf Daten während der Mausbewegung. Verwenden Sie die Mausposition, um die neuen relativen Positionen newPosLeft und newPosTop zu berechnen und die Werte innerhalb eines angemessenen Bereichs zu steuern.
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' }
Methode stoppen, Ereignisüberwachung entfernen, Status löschen und falsche Methode vermeiden ruft
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}) }
Auswahlfeld zuschneiden
auf. Wie beim Ziehen rufen Sie zuerst die resizeStart-Methode auf, speichern die Mausposition, an der das Zuschneiden beginnt, die Größe und Position des Zuschneidefelds, und fügen Sie Ereignis-Listener für resizeBind und stopBind hinzu. Aufgrund der Eigenschaften des Ereignismechanismus muss stopPropagation verwendet werden, um das Blasen von Ereignissen zu verhindern.
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) }
Die Schneidemethode unterteilt das Schneiden in zwei Situationen: Die eine ist das Strecken der rechten Seite, der unteren Seite und der unteren rechten Seite. Das andere ist die Dehnung auf der linken Seite, der oberen Seite und der oberen linken Seite.
Im ersten Fall ändert sich die Position des Auswahlfelds nicht, nur die Größe ändert sich und die Verarbeitung ist relativ einfach. Die neue Größe ist die Originalgröße plus die aktuelle Mausposition minus die Position der Maus zu Beginn des Ziehens. Wenn entweder die Breite oder Höhe den Standard überschreitet, wird die Größe auf eine Größe eingestellt, die gerade die Grenze erreicht. Alle übertreffen den Standard und sind auf neue Größen eingestellt.
Im zweiten Fall ändern sich Position und Größe des Auswahlfelds gleichzeitig. Es ist notwendig, die Größe und Position gleichzeitig zu steuern, um die Grenze nicht zu überschreiten.
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' } } }
Ich glaube, dass Sie die Methode beherrschen, nachdem Sie den Fall in diesem Artikel gelesen haben. Weitere spannende Informationen finden Sie in anderen verwandten Artikeln auf der chinesischen PHP-Website!
Empfohlene Lektüre:
Wie man Vue zum Ausblenden von Divs verwendet
Eine Zusammenfassung, wie die Zustandsobjekte von Vuex verwendet werden
Das obige ist der detaillierte Inhalt vonSo beschneiden Sie Bilder in React. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!