Ce que j'essaie de réaliser, c'est une zone de texte qui commence comme une seule ligne mais qui augmentera jusqu'à 4 lignes et à ce moment-là commencera à défiler si l'utilisateur continue de taper. J'ai une solution partielle qui fonctionne, elle grandit puis s'arrête lorsqu'elle atteint le maximum, mais si vous supprimez du texte, il ne rétrécit pas comme je le souhaite.
C'est ce que j'ai jusqu'à présent.
export class foo extends React.Component {
constructor(props) {
super(props);
this.state = {
textareaHeight: 38
};
}
handleKeyUp(evt) {
// Max: 75px Min: 38px
let newHeight = Math.max(Math.min(evt.target.scrollHeight + 2, 75), 38);
if (newHeight !== this.state.textareaHeight) {
this.setState({
textareaHeight: newHeight
});
}
}
render() {
let textareaStyle = { height: this.state.textareaHeight };
return (
<div>
<textarea onKeyUp={this.handleKeyUp.bind(this)} style={textareaStyle}/>
</div>
);
}
}
De toute évidence, le problème est que scrollHeight
ne diminue pas lorsque height
est défini sur quelque chose de plus grand. Une suggestion sur la façon dont je pourrais résoudre ce problème afin qu'il diminue également si le texte est supprimé?
vous pouvez utiliser taille automatique pour cela
import React, { Component } from 'react';
import autosize from 'autosize';
class App extends Component {
componentDidMount(){
this.textarea.focus();
autosize(this.textarea);
}
render(){
const style = {
maxHeight:'75px',
minHeight:'38px',
resize:'none',
padding:'9px',
boxSizing:'border-box',
fontSize:'15px'};
return (
<div>Textarea autosize <br/><br/>
<textarea
style={style}
ref={c=>this.textarea=c}
placeholder="type some text"
rows={1} defaultValue=""/>
</div>
);
}
}
ou si vous préférez les modules react https://github.com/andreypopp/react-textarea-autosize
UNE AUTRE APPROCHE SIMPLE (sans package supplémentaire)
export class foo extends React.Component {
handleKeyDown(e) {
e.target.style.height = 'inherit';
e.target.style.height = `${e.target.scrollHeight}px`;
// In case you have a limitation
// e.target.style.height = `${Math.min(e.target.scrollHeight, limit)}px`;
}
render() {
return <textarea onKeyDown={this.handleKeyDown} />;
}
}
Le problème lorsque vous supprimez le texte et la zone de texte ne rétrécit pas est parce que vous oubliez de définir cette ligne
e.target.style.height = 'inherit';
Pensez à utiliser onKeyDown car il fonctionne pour toutes les clés alors que d'autres ne le peuvent pas ( w3schools )
Si vous avez padding
ou border
de top
ou bottom
. ( référence )
handleKeyDown(e) {
// Reset field height
e.target.style.height = 'inherit';
// Get the computed styles for the element
const computed = window.getComputedStyle(e.target);
// Calculate the height
const height = parseInt(computed.getPropertyValue('border-top-width'), 10)
+ parseInt(computed.getPropertyValue('padding-top'), 10)
+ e.target.scrollHeight
+ parseInt(computed.getPropertyValue('padding-bottom'), 10)
+ parseInt(computed.getPropertyValue('border-bottom-width'), 10);
e.target.style.height = `${height}px`;
}
J'espère que cela peut aider.
vous pouvez même le faire avec des références de réaction. comme définition ref à l'élément
<textarea ref={this.textAreaRef}></textarea> // after react 16.3
<textarea ref={textAreaRef=>this.textAreaRef = textAreaRef}></textarea> // before react 16.3
et mettez à jour la hauteur sur componentDidMount
ou componentDidUpdate
selon vos besoins. avec,
if (this.textAreaRef) this.textAreaRef.style.height = this.textAreaRef.scrollHeight + "px";
Vraiment simple si vous utilisez des hooks "useRef ()".
css:
.text-area {
resize: none;
overflow: hidden;
min-height: 30px;
}
composant réactif:
export default () => {
const textRef = useRef<any>();
const onChangeHandler = function(e: SyntheticEvent) {
const target = e.target as HTMLTextAreaElement;
textRef.current.style.height = "30px";
textRef.current.style.height = `${target.scrollHeight}px`;
};
return (
<div>
<textarea
ref={textRef}
onChange={onChangeHandler}
className="text-area"
/>
</div>
);
};
Utilisez simplement le crochet useEffect
qui récupérera la hauteur pendant le rendu:
import React, { useEffect, useRef, useState} from "react";
const defaultStyle = {
display: "block",
overflow: "hidden",
resize: "none",
width: "100%",
backgroundColor: "mediumSpringGreen"
};
const AutoHeightTextarea = ({ style = defaultStyle, ...etc }) => {
const textareaRef = useRef(null);
const [currentValue, setCurrentValue ] = useState("");// you can manage data with it
useEffect(() => {
textareaRef.current.style.height = "0px";
const scrollHeight = textareaRef.current.scrollHeight;
textareaRef.current.style.height = scrollHeight + "px";
}, [currentValue]);
return (
<textarea
ref={textareaRef}
style={style}
{...etc}
value={currentValue}
onChange={e=>{
setCurrentValue(e.target.value);
//to do something with value, maybe callback?
}
/>
);
};
export default AutoHeightTextarea;