javascript/react 动态高度文本区域(最大停止)
Posted
技术标签:
【中文标题】javascript/react 动态高度文本区域(最大停止)【英文标题】:javascript/react dynamic height textarea (stop at a max) 【发布时间】:2017-01-17 00:14:38 【问题描述】:我想要实现的是一个 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>
);
很明显,当height
设置为更大的值时,scrollHeight
不会缩小。关于如何解决此问题的任何建议,以便在删除文本时它也会缩小?
【问题讨论】:
【参考方案1】:另一种简单的方法(无需额外的软件包)
export class foo extends React.Component
handleKeyDown(e)
e.target.style.height = 'inherit';
e.target.style.height = `$e.target.scrollHeightpx`;
// 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
或border
或top
或bottom
。 (reference)
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 = `$heightpx`;
我希望这会有所帮助。
【讨论】:
TextArea 有初始长文本时失败【参考方案2】:你可以使用autosize
LIVE DEMO
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
【讨论】:
这很棒。谢谢! 链接失效了。【参考方案3】:只需使用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;
【讨论】:
您应该在帖子中添加说明。仅包含代码而没有解释的帖子往往会不受欢迎:) @bikram 同意?【参考方案4】:你甚至可以使用 react refs 来做到这一点。将 ref 设置为元素
<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";
【讨论】:
【参考方案5】:如果你使用钩子“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.scrollHeightpx`;
;
return (
<div>
<textarea
ref=textRef
onChange=onChangeHandler
className="text-area"
/>
</div>
);
;
【讨论】:
你不需要 ref 来做到这一点。只有事件才会起作用。 @Pier-AlexandreBouchard 是的,我同意。【参考方案6】:实际上,您可以通过 useState
和 useEffect
摆脱这种情况
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 />
【讨论】:
【参考方案7】:我喜欢使用 this.yourRef.current.offsetHeight。由于这是一个文本区域,它不会像<div style=height:"min-content">this.state.message</div>
那样响应height:min-content
。所以我不使用
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>
【讨论】:
【参考方案8】:运行此代码即可...
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;
【讨论】:
以上是关于javascript/react 动态高度文本区域(最大停止)的主要内容,如果未能解决你的问题,请参考以下文章