javascript/react 动态高度 textarea(停在最大值)

IT技术 javascript html css reactjs
2021-04-29 12:06:50

我想要实现的是一个文本区域,它从一行开始,但会增长到 4 行,如果用户继续键入,则此时开始滚动。我有一个部分解决方案有点工作,它会增长,然后在达到最大值时停止,但是如果您删除文本,它不会像我希望的那样缩小。

这就是我迄今为止所拥有的。

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>
    );
  }
}

显然,问题是scrollHeightheight设置为更大的值时不会缩小关于如何解决此问题的任何建议,以便在删除文本时它也会缩小?

4个回答

另一个简单的方法(没有额外的包)

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} />;
  }
}

删除text时textarea不收缩的问题是因为忘记设置这一行

e.target.style.height = 'inherit';

考虑使用 onKeyDown 因为它适用于所有键,而其他键可能不适用(w3schools

如果你有paddingbordertopbottom参考

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`;
}

我希望这会有所帮助。

您可以为此使用自动调整大小

现场演示

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>
        );
    }
}

或者如果你更喜欢reactmodulehttps://github.com/andreypopp/react-textarea-autosize

只需使用useEffect钩子即可在渲染器期间获取高度:

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;

你甚至可以用 react refs 来做到这一点。作为将 ref 设置为元素

<textarea ref={this.textAreaRef}></textarea> // after react 16.3
<textarea ref={textAreaRef=>this.textAreaRef = textAreaRef}></textarea> // before react 16.3

和更新的高度componentDidMountcomponentDidUpdate为您的需要。和,

if (this.textAreaRef) this.textAreaRef.style.height = this.textAreaRef.scrollHeight + "px";