- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试制作一个可重用的 React text-clamp 组件。用户传入要呈现的行数和他们想要显示的文本,然后组件呈现他们的文本,在指定的行数处将其 chop 并在末尾插入省略号 (...)。
我计算在哪里 chop 文本和插入省略号的方法是一次添加一个单词,直到 clientHeight
文本大于 clientHeight
容器 div。
虽然它有效,但我在 chrome 开发工具中看到以下内容:
[Violation] Forced reflow while executing JavaScript took 179ms
.
这可能是因为阅读 clientHeight
forces reflow .
这是我的代码:
class TextClamp extends React.PureComponent {
constructor(props) {
super(props);
this.renderText = this.renderText.bind(this);
this.state = {
words: this.props.textToDisplay.split(' '),
};
}
componentDidMount() {
this.renderText();
}
renderText(isResizing = false) {
const textEl = this.displayedText;
const clampContainer = this.clampContainer;
const heightToStop = isResizing ? clampContainer.style.height : this.letterHeightText.clientHeight * this.props.linesToRender;
const dummyText = this.dummyText;
const dummyDiv = this.dummyDiv;
const words = this.state.words;
const numWords = words.length;
dummyDiv.style.cssText = `width: ${clampContainer.clientWidth}px; position: absolute; left: -1000px;`;
let i = this.props.estimatedWordCount || 20;
let strToRender = words.slice(0, i).join(' ');
dummyText.textContent = strToRender;
if (dummyText.clientHeight <= heightToStop && i>=numWords) {
return;
}
while (dummyText.clientHeight <= heightToStop && i<numWords) {
dummyText.textContent += ' ' + words[i++];
};
strToRender = dummyText.textContent;
while (dummyText.clientHeight > heightToStop) {
strToRender = strToRender.substring(0, strToRender.lastIndexOf(' '));
dummyText.textContent = strToRender + '\u2026';
}
textEl.textContent = dummyText.textContent;
}
render() {
const estimatedHeight = this.props.estimatedHeight || 20 * this.props.linesToRender;
const containerStyle = { height: estimatedHeight, overflow: 'hidden'};
if (typeof window !== 'undefined') {
const dummyDiv = document.createElement('div');
const dummyText = document.createElement('p');
dummyDiv.appendChild(dummyText);
this.dummyDiv = dummyDiv
this.dummyText = dummyText
document.body.appendChild(dummyDiv);
}
return (
<div style={containerStyle} ref={(input) => {this.clampContainer = input;}}>
<p ref={(input) => {this.displayedText = input;}}>{this.props.textToDisplay}</p>
<p style={{visibility: 'hidden'}} ref={(input) => {this.letterHeightText = input;}}>Q</p>
</div>
);
}
}
所以基本上,组件的主要主力是 renderText()
功能。在那里,我一次添加一个词,直到文本的高度大于其容器的高度。从那里,我删除了最后一个词并添加了省略号。
我所做的优化如下:
estimatedWordCount 允许每次添加一个单词的循环不必每次都从头开始。
我通过将实际容器 div 的尺寸复制到屏幕外来计算应该显示的文本,position:absolute
div,因此它与其他 DOM 元素没有交互。
然而,即使经过我的优化,chrome 仍然提示由于 javascript 导致的重排花费的时间太长。
我的 renderText()
是否有任何优化?我可以做的功能以避免阅读 clientHeight
这么频繁?
最佳答案
满足规定的要求:
The user passes in the number of lines to render and the text they want to display, and the component renders their text, cutting it off at the specified number of lines and inserting an ellipsis (...) at the end.
一种方法是放弃高度计算而只担心宽度,添加单词直到我们的行宽度与其容器碰撞,并跟踪添加的行直到达到指定行的最大数量。
这种方法大大加快了速度,因为它避免了过多地接触 DOM。有趣的是,我看到渲染时间加快了 3 倍。使用此方法和一些其他优化,请参阅内联注释以了解更多信息。
Take a look at this component这是我编码的,在此处列出以供引用。另请查看下面的示例用法。
import React, {Component} from "react";
class TextClamp extends Component {
constructor(props) {
super(props);
this.state = {
lines: []
}
}
computeText = () => {
// Our desired text width we are trying to hit
const width = this.container.clientWidth;
// we reverse the word list so can take grab elements efficiently using pops
// pops are O(1) while unshift is O(n).
let words = this.props.textToDisplay.split(/\s+/).reverse();
// we keep lines separate, rather than all concatenated together with \n,
// because react will remove new lines unless we resort to using
// dangerouslySetInnerHTML, which we should prefer to avoid
let lines = [];
// we reset any previous text to avoid bugs if we happen to call computeText more than once
this.textContainer.textContent = "";
let lineNumber = 0;
// first word and line init
let word = words.pop();
lines[lineNumber] = "";
// Our goal is to build up the lines array to contain at most
// linesToRender elements, with each line's width being at most
// the width of our container
while (word ) {
// add our word
lines[lineNumber] += " " + word;
this.textContainer.textContent += " " + word;
// too wide, so we instead start a new line
if (this.textContainer.clientWidth >= width) {
// add back the word for the next line
words.push(word);
// remove our last added and clean up
lines[lineNumber] = lines[lineNumber].slice(0, -word.length).trim();
// already at linesToRender, therefore we cannot render complete text,
// so we add our ellipsis
if(lineNumber === this.props.linesToRender-1) {
lines[lineNumber] += " ..."
break;
}
// remove current text so we can calculate our next line width
this.textContainer.textContent = "";
console.log(lineNumber, this.props.linesToRender)
lineNumber++;
// init our next line
lines[lineNumber] = "";
}
// next word
word = words.pop()
console.log(word)
}
// clean up just like we added a new line,
lines[lineNumber] = lines[lineNumber].trim();
// remove current text so when react renders it has a clean slate to add text elements
this.textContainer.textContent = "";
this.setState({
lines: lines,
})
};
componentDidMount() {
this.computeText();
}
render() {
// we need our 'pre for our whiteSpace, to explicitly control when our text breaks
const containerStyle = {whiteSpace: 'pre'};
// we need 'inline-block' so our p tag's width reflects the amount of text added, not its parent
const textStyle = {display: 'inline-block'};
// put line breaks between all the lines, except the first
const lines = this.state.lines.map((text, i) => i ? [<br/>, text] : text);
console.log(this.state.lines)
return (
<div style={containerStyle} ref={(input) => {
this.container = input;
}}>
<p style={textStyle} ref={(input) => {
this.textContainer = input;
}}>
{lines}
</p>
</div>
);
}
}
TextClamp.defaultProps = {
linesToRender: 2,
textToDisplay: ""
};
用法:
const exampleText = "This is an example piece of text. It should properly break lines at the correct width of it's parent, until it a certain max number of lines have been created. However sometimes the text, is too long to fit on the specified number of lines. At that point the line should be cut off."
const lines = 3
<TextClamp linesToRender={lines} textToDisplay={exampleText} />
关于javascript - React Text Clamp 的性能改进?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45091779/
Julia 有 two methods for limiting variables to ranges of numbers : clamp 和 clamp!。使用点表示法,clamp. 也可以用于
我正在使用 Rust 和 WebAssembly 操作像素数据,并且正在努力使用操作的像素创建新的 ImageData。 当我得到我的 ImageData 时的数据,它返回 Clamped> f
我访问了这个问题的问题: Android SAX parser not getting full text from between tags因为我有类似的问题。我用这一侧的一项陈述解决了我的问题,但
我在开发的游戏中使用 Mathhelper.Clamp 时遇到了问题。这是导致我出现问题的代码片段: if (background.position.Y == 0) { player.posi
我正在放大一个元素并尝试更改 -webkit-line-clamp。它的工作原理是它在更改后显示了正确的行数,但它不起作用的原因是省略号和链接(在文本之后)没有移动到(新)末尾。 查看CodePen
我想对二维数组上的 PyTorch 张量执行类似于 np.clip 的操作。更具体地说,我想将每一列剪裁在特定的值范围内(依赖于列)。例如,在 numpy 中,你可以这样做: x = np.array
我正在编写一个表示 LED 的类。 r、g 和 b 的基本 3 个 uint 值在 0 到 255 范围内。 我是 C# 的新手,从 uint1 开始,它比我想要的 8 位大。在编写自己的 Clamp
给定: let a = 4.2 let b = -1.3 let c = 6.4 我想知道将这些值限制在给定范围内的最简单、最快捷的方法,比如 0...5,这样: a -> 4.2 b -> 0 c
我很想使用 CSS 中的 clamp 函数实现流畅的字母间距。但是因为我喜欢我的字母间距很紧,所以我需要在公式中包含三个负值,并且现在尝试了几个小时来弄清楚这个。我是否必须切换最小值和最大值,因为它们
我正在使用 -webkit-line-clamp 属性来在 Chrome 上实现多行省略号。我们已经适本地设置了高度和最大高度,以便我们看到准确的 N 行和正确的省略号。但是,一旦我们在浏览器中放大或
我正在开发一个在 z 轴上旋转对象的游戏。我需要将总旋转限制为 80 度。我尝试了以下代码,但它不起作用。 minAngle = -40.0f 和 maxAngle = 40.0f Vector3 p
给定 1 到 16 之间的精度 p,我想将 AVX2 整数寄存器限制在 -p/2 和 p/2 之间>。我目前使用 std::clamp 对非 AVX2 整数执行此操作。 有没有办法用 AVX2 做到这
给定 1 到 16 之间的精度 p,我想将 AVX2 整数寄存器限制在 -p/2 和 p/2 之间>。我目前使用 std::clamp 对非 AVX2 整数执行此操作。 有没有办法用 AVX2 做到这
我在它们之间显式转换了类型,但错误仍然存在 var destX:CGFloat = 5.0 func clamp(value: CGFloat, min: CGFloat, max: CGFl
我有一个 Vector2 变量,其中 vector.x 和 vector.y 已被限制,因此两者都只允许有 0 到 4 之间的值。显然,这使我在坐标 2 周围有一个二次空间,2 到移动游戏对象。但我想
VS2015 不会编译我的代码,说命名空间“std”没有成员“clamp”,尽管 intellisense 可以很好地识别它并告诉我参数和返回值。是的,我已经包含了标题。 #include #inc
我在 PHP 中编写了一个函数来“钳制”数字,但我想知道该函数是否在该语言中原生存在。 我在数学部分阅读了 PHP.net 文档,但找不到。 基本上我的函数所做的是它接受一个变量、一个可能值的数组和一
我正在尝试制作一个可重用的 React text-clamp 组件。用户传入要呈现的行数和他们想要显示的文本,然后组件呈现他们的文本,在指定的行数处将其 chop 并在末尾插入省略号 (...)。 我
为什么 -webkit-line-clamp 没有使用 text-align:justify 显示正确的省略号。它与 text-align:left/right 一起工作良好。 请提出任何技巧。 di
我有链接 some really long text 和这个 CSS .module { width: 250px; overflow: hidden; } .line-clamp
我是一名优秀的程序员,十分优秀!