Cette fois, je vais vous montrer comment recadrer des images dans React, et quelles sont les précautions à prendre pour recadrer des images dans React. Ce qui suit est un cas pratique, jetons un coup d'oeil.
Démarrer
J'écris Vue depuis plus d'un an et je sens que j'ai rencontré un goulot d'étranglement. Je vais apprendre React pour découvrir ce sentiment. Il m'est récemment arrivé d'utiliser Vue pour écrire un composant de recadrage d'image basé sur cropperJS, j'ai donc passé quelques nuits à l'écrire à nouveau en utilisant React. Le projet d'adresse de code
est développé à l'aide de create-react-app, ce qui permet d'économiser beaucoup d'efforts dans la configuration du webpack. Il prend en charge eslint, l'actualisation automatique et d'autres fonctions. Il suffit d'installer npm et de démarrer npm avant utilisation. Il est recommandé aux personnes qui débutent de réagir de l'essayer également.
Le projet est relativement simple à écrire et la configuration personnalisée est relativement pauvre. Cependant, il complète également la fonction de base de recadrage des images. J'espère qu'il pourra aider les amis nouveaux à réagir et à comprendre. composant d'image de recadrage.
La structure du composant est comme ceci.
<!--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
La principale tâche d'ImageUploader est de télécharger des images, d'écouter l'événement de changement d'entrée et d'appeler la méthode handleImgChange du composant parent Cropper , Cette méthode définit la valeur imageValue liée à l'élément img, ce qui amènera l'élément img à déclencher l'événement de chargement.
handleImgChange = e => { let fileReader = new FileReader() fileReader.readAsDataURL(e.target.files[0]) fileReader.onload = e => { this.setState({...this.state, imageValue: e.target.result}) } }
L'événement de chargement déclenche la méthode setSize de Cropper, qui peut définir la position et la taille initiales de l'image et de la zone de sélection de recadrage. Actuellement, le paramètre par défaut de la zone de sélection de recadrage est que la taille correspond à 80 % de l'image et s'affiche au milieu.
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' } }
Il existe également une méthode getCropData sur Cropper, qui imprimera et renverra les paramètres de recadrage
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
Play. encore une fois La structure de selectArea. Il convient de noter que l'attribut curseur de .top-resize est n-resize, et les gauche, droite et bas correspondants sont w-resize, e-resize et 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>
le valeur d'état de selectArea respectivement. Définissez comme ceci, selectArea enregistre les paramètres lorsque vous faites glisser la zone de sélection, resizeArea enregistre les paramètres lors du recadrage de la zone de sélection, le conteneur est l'élément .image-principal et el est l'événement.target lorsque l'événement est. déclenché.
this.state = { selectArea: null, el: null, container: null, resizeArea: null }
Faites glisser la zone de sélection
Appuyez sur la souris dans la zone .select, déclenchez l'événement mouseDown et appelez la méthode dragStart.
L'utilisation de method = e => {} peut éviter d'utiliser this.method.bind(this) dans jsx
Dans cette méthode, enregistrez d'abord la souris lorsque la souris est enfoncée. Position, le distance relative entre le cadre de recadrage et l'image et la distance de déplacement maximale du cadre de recadrage, puis ajoutez des écouteurs d'événements
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 et stopBind proviennent de la
this.moveBind = this.move.bind(this) this.stopBind = this.stop.bind(this)
méthode move, lorsque la souris bouge Calculez les nouvelles positions relatives newPosLeft et newPosTop en fonction de l'enregistrement de la nouvelle position de la souris et contrôlez les valeurs dans une plage raisonnable
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' }
méthode d'arrêt, supprimez l'écoute des événements, effacez l'état et éviter les appels de méthode incorrects
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}) }
Boîte de sélection de recadrage
Identique au glisser-déposer, appelez d'abord la méthode resizeStart, enregistrez la position de la souris où le recadrage commence, la taille et la position de la zone de recadrage, et ajoutez à propos de la surveillance des événements resizeBind et stopBind. Notez qu'en raison des caractéristiques du mécanisme d'événement de React, stopPropagation doit être utilisé pour empêcher la propagation d'événements. L'utilisation de false comme troisième paramètre de surveillance des événements n'est pas valide.
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) }
La méthode de coupe divise la coupe en deux situations : l'une est l'étirement du côté droit, du côté inférieur et du côté inférieur droit. L'autre est l'étirement sur le côté gauche, le côté supérieur et le côté supérieur gauche.
Dans le premier cas, la position de la case de sélection ne changera pas, seule la taille changera, et le traitement est relativement simple. La nouvelle taille correspond à la taille d'origine plus la position actuelle de la souris moins la position de la souris au début du déplacement. Si la largeur ou la hauteur dépasse la norme, la taille est définie sur une taille qui atteint juste la limite. Tous dépassent la norme et sont définis dans de nouvelles tailles.
Dans le deuxième cas, la position et la taille de la case de sélection changeront en même temps. Il est nécessaire de contrôler la taille et la position en même temps pour ne pas dépasser la limite.
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' } } }
Je pense que vous maîtrisez la méthode après avoir lu le cas dans cet article. Pour des informations plus intéressantes, veuillez prêter attention aux autres articles connexes sur le site Web chinois de php !
Lecture recommandée :
Comment utiliser vue pour masquer les divs
Un résumé de la façon dont les objets d'état de vuex sont utilisés
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!