从字符串中获取 x 像素文本的最可靠方法,javascript
我的 JavaScript 文件中有一个包含大量文本 text 的字符串。我还有一个元素 div#container ,它的样式(使用单独的 CSS)具有潜在的非标准 line-height
、font-size
、< code>font-face,也许还有其他。它有固定的高度和宽度。
我想获得可以容纳 div#container 的最大文本量,而不会从字符串中溢出。这样做的最佳方法是什么?
这需要能够使用标签格式化的文本,例如:
<strong>Hello person that is this is long and may take more than a</strong>
line and so on.
目前,我有一个适用于纯文本的 JQuery 插件,代码如下:
// returns the part of the string that cannot fit into the object
$.fn.func = function(str) {
var height = this.height();
this.height("auto");
while(true) {
if(str == "") {
this.height(height);
return str; // the string is empty, we're done
}
var r = sfw(str); // r = [word, rest of String] (sfw is a split first word function defined elsewhere
var w = r[0], s = r[1];
var old_html = this.html();
this.html(old_html + " " + w);
if(this.height() > height)
{
this.html(old_html);
this.height(height);
return str; // overflow, return to last working version
}
str = s;
}
}
更新:
数据如下所示:
<ol>
<li>
<h2>Title</h2>
<ol>
<li>Character</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
<ol>
<li>This can be split from other</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
</li> <li>
<h2>Title</h2>
<ol>
<li>Character</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
<ol>
<li>This can be split from other</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
</li>
</ol>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
好吧,让我尝试解决它;)实际上在考虑解决方案时,我注意到我对您的需求了解不够,所以我决定开发简单的 JavaScript 代码并向您展示结果;尝试后你可以告诉我出了什么问题,以便我可以修复/更改它,好吗?
我使用纯 JavaScript,没有 jQuery(如果需要可以重写)。原理和你的jQuery插件类似:如果
sfw
函数那样的单词;它可以更改),container.innerHTML = "My String has a link 时,我会看到“
My String has a link
” ,因此“未完成”标签不会影响容器的大小(至少在我测试的所有浏览器中)HTML 页面来测试它:
可能的改进/更改:
fullText
写回到容器中(我也不会更改)“ourentence”
,则可见的可能只是第一个(“our”
),并且“sentence”应该被删除(>overflow:hidden
将以这种方式工作)。就我而言,我将逐个字符附加,因此我的结果可以是“我们发送的”
。同样,这不是算法的复杂部分,因此根据您的 jQuery 插件代码,您可以更改我的以处理单词。欢迎提出问题、评论、发现的错误;)我在 IE9、FF3.6、Chrome 9 中测试了它
更新: 根据
...例如,我有包含内容的容器:
在这种情况下,浏览器的行为方式如下(容器中的字符串和我看到的内容根据算法显示):
算法的结果是字符串
"< ;strong>带有 "
的强文本 - 带有",有什么不好的。在这种情况下我需要处理的是,如果我们找到结果字符串(根据算法
"Strong text with ),我们需要删除最后一个“未关闭”标签(在我们的例子中为
" ),因此在关闭标签以获得有效的 html 之前,我添加了以下内容:
可能有点懒惰的实现,但如果速度减慢,可以对其进行调整向下。这里所做的就是
>
的标签(在我们的例子中,它返回[") ;
"),
croppedText
字符串的末尾,那么我们做完后将其删除,结果字符串变成
"< strong>带有"的强文本
UPDATE2 例如,谢谢您,所以我发现您不仅仅有嵌套标签,但它们也有“树”结构,确实我没有考虑到它,但它仍然可以修复;)一开始我想写我合适的“解析器”,但当我总是得到一个例子不起作用,所以我认为最好找到已经编写的解析器,有一个: 纯 JavaScript HTML 解析器。还有一个粗暴:
但对于你的例子来说它是有效的;该库没有考虑开始标签的位置,但
我认为有了这个假设,这个库就很好用。那么结果函数如下所示:
well, let me try to solve it ;) actually thinking about solution I noticed that I don't know enough about requirements you have, so I decided to develop simple JavaScript code and show you result; after trying it you can tell me what's wrong so I can fix/change it, deal?
I used pure JavaScript, no jQuery (it can be rewritten if needed). The principle is similar to your jQuery plugin:
sfw
function does; it can be changed)container.innerHTML = "My String has a link <a href='#'";
in browser I see "My String has a link
", so "unfinished" tag does not influence size of container (at least in all browsers where I tested)HTML page to test it:
Possible improvements / changes:
fullText
back into container if needed (which I also do not change)sfw
function, so you can change it easily."our sentence"
, it is possible that visible will be only first one ("our"
), and "sentence" should be cut (overflow:hidden
will work this way). In my case, I will append character by character, so my result can be"our sent"
. Again, this is not a complex part of algorithm, so based on your jQuery plugin code, you can change mine to work with words.Questions, remarks, bugs found are welcome ;) I tested it in IE9, FF3.6, Chrome 9
UPDATE: Accroding to an issue with
<li>, <h1>
... E.g. I have container with content:In this case browser behaves this way (string by string what is in container and what I see it shows according to the algorithm):
and result of algorithm is string
"<strong><i>Strong text with <u</i></strong>"
- with"<u"
, what is not nice. What I need to process in this case is that if we found our result string ("<strong><i>Strong text with <u"
according to the algorithm), we need to removed last "unclosed" tag ("<u"
in our case), so before closing tags to have valid html I added the following:probably a bit lazy implementation, but it can be tuned if it slows down. What is done here
>
(in our case it returns["<strong", "<i", "<u"]
);"<u"
)croppedText
string, then we remove itafter doing it, the result string becomes
"<strong><i>Strong text with </i></strong>"
UPDATE2 thank you for example, so I see that you don't have just nested tags, but they also have "tree" structure, indeed I didn't take it into account, but it still can be fixed ;) At the beginning I wanted to write my appropriate "parser", but all the time I get an example when I does not work, so I thought it is better to find already written parser, and there is one: Pure JavaScript HTML Parser. There is also one shag to it:
but for your example it works; that library didn't take into account position of opening tag, but
I think that with that assumptions this library is nice to use. Then result function looks like:
要获得尽可能长的第一行:
visibility:hidden;
的 DIV(这样它将具有尺寸),但将其定位为position:absolute;
这样就不会中断您的页面流DIV
相同的值DIV
相同,但保留width:auto;
DIV
的宽度。结果是您可以输入的文本。
如果您需要找到适合容器的行数量以保持
height:auto;
并设置固定,请调整算法>宽度
。自动调整文本区域也使用了相同的技术,这些文本区域在用户输入文本时自动增长。
To get longest possible first line:
visibility:hidden;
(so it will have dimension) but position it asposition:absolute;
so it won't break your page flowDIV
DIV
but keepwidth:auto;
DIV
's width.The result is the text you can put in.
Adjust the algorithm if you need to find amount of lines that fit into container to keep
height:auto;
and set fixedwidth
.The same technique is used by auto-adjusting textareas that auto-grow while users type in text.
为了解决这个问题,您将需要额外的信息:
至于“在哪里切割”问题,您可能必须在输入字符串中的战略点处注入唯一的
锚标记(例如...在输入中的每个开始标记之前?)。然后,您可以测试每个锚点的布局位置并找到中断输入的位置。
找到最符合逻辑的中断点后,您需要在前半部分的末尾添加标签以将其关闭,并在下半部分的前面添加标签以将其打开。因此,当您之前解析输入字符串以查找开始标记时,您在注入
时保留了“标记堆栈”列表。查找与此特定相关的标签堆栈,然后根据需要添加标签。
我可以发现两个陷阱:
处中断。
相反,最终,在我看来,您正在等待 HTML5 的列构造。
To solve this, you're going to need additional information:
As for the 'where to chop' question, you'll probably have to inject unique
<a name="uniq"/>
anchor tags at strategic points in your input string (say ... before each opening tag in the input?). Then, you can test the layed-out position of each anchor and find where to break the input.Having found the most logical point to break, you'll need to add tags at the end of the first half to close it off, and add tags at the front of the next half to open it. So when you parsed your input string to find the opening tags previously, you kept a list of the 'tag stack' when you injected the
<a/>
. Lookup the tag stack that's relevant for this paritcular and then add the tags as required.I can spot 2 gotchas with this:
<a/>
insteadUltimately, it seems to me you're waiting for HTML5's column construct.
您是否只是想格式化段落中的第一行? CSS :first-line 伪选择器是否有效适合您的应用程序?
Are you just trying to format the first line in a paragraph? Would the CSS :first-line pseudo-selector work for your application?
您可以使用 getCompulatedStyle 来找出内联元素的宽度(即它有
display: inline
属性):如果发现该元素的宽度大于其容器的宽度,您将逐步删除一些文本,直到它适合为止。
You could use getComputedStyle to find out the width of an inline element (i.e. it has the
display: inline
property):If it turns out that this element's width is larger than its container's width, you would remove some text step by step until it fits in.