web-dev-qa-db-ja.com

javascript / react動的高さテキストエリア(最大で停止)

私が達成しようとしているのは、最初は1行で始まるテキストエリアですが、最大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がより大きな値に設定されても縮小されないことです。これを修正してテキストが削除された場合に縮小する方法についての提案はありますか?

10
jcmitch

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

または、リアクションモジュールが必要な場合 https://github.com/andreypopp/react-textarea-autosize

16

別の簡単なアプローチ(追加パッケージなし)

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

テキストを削除してtextareaが縮小しない場合の問題は、この行を設定し忘れたためです

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

OnKeyDownの使用を検討してください。他のキーでは機能しないのに、すべてのキーで機能します( w3schools

paddingまたはbordertopまたはbottomある場合参照

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

これがお役に立てば幸いです。

10
Tatsu

リアクション参照でそれを行うこともできます。要素への参照の設定として

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

必要に応じて、componentDidMountまたはcomponentDidUpdateの高さを更新します。と、

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

「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>
  );
};
1
sajan

レンダラー中に高さを取得する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;