Rya*_*hel 7 html javascript css reflow reactjs
注意:据我所知,这不是重复项,因为使用contentEditablediv似乎不是一个很好的选择。它有很多问题(没有占位符文本,需要使用dangerouslySetInnerHTML技巧来更新文本,选择光标过于挑剔,其他浏览器问题,等等),我想使用文本区域。
我目前正在为我的React textarea组件执行以下操作:
componentDidUpdate() {
let target = this.textBoxRef.current;
target.style.height = 'inherit';
target.style.height = `${target.scrollHeight + 1}px`;
}
Run Code Online (Sandbox Code Playgroud)
这可以工作,并且允许文本区域在添加和删除换行符时动态地增加和缩小高度。
问题在于,每一次文本更改都会发生重排。这在应用程序中造成很多滞后。如果我在文本区域中按住一个键,则在附加字符时会有延迟和滞后。
如果我取消target.style.height = 'inherit';生产线,那么滞后就会消失,所以我知道这是由于这种不断回流造成的。
我听说设置overflow-y: hidden可能会消除持续的重排,但是在我看来并不是这样。同样,设置target.style.height = 'auto';不允许动态调整大小。
我目前已经开发了一种可行的解决方案,但我不喜欢它,因为每次文本更改时它都是O(n)操作。我只计算换行的数量并相应地设置大小,如下所示:
// In a React Component
handleMessageChange = e => {
let breakCount = e.target.value.split("\n").length - 1;
this.setState({ breakCount: breakCount });
}
render() {
let style = { height: (41 + (this.state.breakCount * 21)) + "px" };
return (
<textarea onChange={this.handleMessageChange} style={style}></textarea>
);
}
Run Code Online (Sandbox Code Playgroud)
我认为三十点的建议可能是最好的。他链接的Material UI textarea有一个非常聪明的解决方案。
它们创建了一个隐藏的绝对定位的文本区域,该区域模仿实际文本区域的样式和宽度。然后他们将您键入的文本插入该文本区域并获取其高度。由于它的位置绝对正确,因此无需进行回流焊计算。然后,他们使用该高度作为实际文本区域的高度。
我不完全了解他们的代码在做什么,但是我根据自己的需要进行了最小化的重新设计,而且看起来效果很好。以下是一些摘要:
.shadow-textarea {
visibility: hidden;
position: absolute;
overflow: hidden;
height: 0;
top: 0;
left: 0
}
Run Code Online (Sandbox Code Playgroud)
<textarea ref={this.chatTextBoxRef} style={{ height: this.state.heightInPx + "px" }}
onChange={this.handleMessageChange} value={this.props.value}>
</textarea>
<textarea ref={this.shadowTextBoxRef} className="shadow-textarea" />
Run Code Online (Sandbox Code Playgroud)
componentDidUpdate() {
this.autoSize();
}
componentDidMount() {
this.autoSize();
}
Run Code Online (Sandbox Code Playgroud)
autoSize = () => {
let computedStyle = window.getComputedStyle(this.chatTextBoxRef.current); // this is fine apparently..?
this.shadowTextBoxRef.current.style.width = computedStyle.width; // apparently width retrievals are fine
this.shadowTextBoxRef.current.value = this.chatTextBoxRef.current.value || 'x';
let innerHeight = this.shadowTextBoxRef.current.scrollHeight; // avoiding reflow because we are retrieving the height from the absolutely positioned shadow clone
if (this.state.heightInPx !== innerHeight) { // avoids infinite recursive loop
this.setState({ heightInPx: innerHeight });
}
}
Run Code Online (Sandbox Code Playgroud)
有点骇人听闻,但似乎效果很好。如果任何人都可以改善或改善它,或者用更优雅的方法清理它,我将接受他们的回答。但是,考虑到Material UI使用它,这似乎是最好的方法,这是我到目前为止尝试过的唯一一种方法,它消除了在足够复杂的应用程序中造成延迟的昂贵的回流计算。
Chrome浏览器仅报告高度变化时发生一次重熔,而不是每次按键时。因此,当文本区域增大或缩小时,仍然存在30ms的滞后时间,但这比每次按键或更改文本都要好得多。使用此方法可以将滞后时间减少99%。
| 归档时间: |
|
| 查看次数: |
366 次 |
| 最近记录: |