javascript / react动态高度textarea(最多停止)

时间:2016-09-08 23:14:27

标签: javascript html css reactjs

我想要实现的是一个textarea,它以单行开头,但最多会增长到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>
    );
  }
}

显然,当scrollHeight设置为更大时,问题height不会缩减。有关如何修复此问题的任何建议,如果文本被删除,它也会缩减吗?

8 个答案:

答案 0 :(得分:12)

您可以{/ 3}}使用

autosize

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

或者您更喜欢反应模块LIVE DEMO

答案 1 :(得分:5)

只需使用Traceback (most recent call last): File "program.py", line 24, in <module> answer = format_days(['Mon', 'Wed', 'Fri']) File "program.py", line 14, in format_days days = days.replace(i,REPLACEMENTS[i]) AttributeError: 'list' object has no attribute 'replace' 钩子,它将在渲染器中拾取高度:

useEffect

答案 2 :(得分:2)

使用钩子“ useRef()”真的很简单。

css:

.text-area {
   resize: none;
   overflow: hidden;
   min-height: 30px;
}

反应对象:

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

答案 3 :(得分:1)

另一种简单的方法(无附加包)

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

删除文本和文本区域时不会缩回的问题是因为忘记设置此行

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

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

如果您有paddingborder中的topbottomreference

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

我希望这会有所帮助。

答案 4 :(得分:1)

您甚至可以使用react refs做到这一点。设置对元素的引用

<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";

答案 5 :(得分:0)

我喜欢使用this.yourRef.current.offsetHeight。由于这是一个文本区域,因此它不会像height:min-content那样对<div style={{height:"min-content"}}>{this.state.message}</div>做出响应。因此,我不使用

uponResize = () => {
 clearTimeout(this.timeout);
  this.timeout = setTimeout(
   this.getHeightOfText.current &&
   this.setState({
    heightOfText: this.getHeightOfText.current.offsetHeight
   }),
  20
 );
};
componentDidMount = () => {
 window.addEventListener('resize', this.uponResize, /*true*/)
}
componentWillUnmount = () => {
 window.removeEventListener('resize', this.uponResize)
}

而是使用

componentDidUpdate = () => {
 if(this.state.lastMessage!==this.state.message){
  this.setState({
   lastMessage:this.state.message,
   height:this.yourRef.current.offsetHeight
  })
 }
}

在隐藏的div上

<div
 ref={this.yourRef}
 style={{
  height:this.state.height,
  width:"100%",
  opacity:0,
  zIndex:-1,
  whiteSpace: "pre-line"
 })
>
 {this.state.message}
</div>

答案 6 :(得分:0)

运行此代码它有效...

$string = trim(preg_replace('/\s\s+/', ' ', $string));

答案 7 :(得分:0)

实际上你可以用 useStateuseEffect

function CustomTextarea({minRows}) {
  const [rows, setRows] = React.useState(minRows);
  const [value, setValue] = React.useState("");
  
  React.useEffect(() => {
    const rowlen = value.split("\n");

    if (rowlen.length > minRows) {
      setRows(rowlen.length);
    }
  }, [value]);

  return (
    <textarea rows={rows} onChange={(text) => setValue(text.target.value)} />
  );
}

用途

<CustomTextarea minRows={10} />
相关问题