Javascript 截断 HTML 文本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3822233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript truncate HTML text
提问by Francisc
Does JavaScript have a way of truncating HTML text without all the headaches of matching tags etc etc?
JavaScript 是否有一种截断 HTML 文本的方法,而无需担心匹配标签等问题?
Thank you.
谢谢你。
采纳答案by Darin Dimitrov
There's nothing built-in javascript. There's a jQuery pluginthat you might take a look at.
没有任何内置的 javascript。您可以查看一个jQuery 插件。
回答by Minouris
I had the same problem, and wound up writing the following to deal with it. It truncates HTML to a give length, cleans up any start / end tags that might have gotten snipped off at the end, and then closes any tags left unclosed:
我遇到了同样的问题,最后写了以下内容来解决它。它将 HTML 截断到给定的长度,清除可能在最后被剪掉的任何开始/结束标签,然后关闭所有未关闭的标签:
function truncateHTML(text, length) {
var truncated = text.substring(0, length);
// Remove line breaks and surrounding whitespace
truncated = truncated.replace(/(\r\n|\n|\r)/gm,"").trim();
// If the text ends with an incomplete start tag, trim it off
truncated = truncated.replace(/<(\w*)(?:(?:\s\w+(?:={0,1}(["']{0,1})\w*{0,1})))*$/g, '');
// If the text ends with a truncated end tag, fix it.
var truncatedEndTagExpr = /<\/((?:\w*))$/g;
var truncatedEndTagMatch = truncatedEndTagExpr.exec(truncated);
if (truncatedEndTagMatch != null) {
var truncatedEndTag = truncatedEndTagMatch[1];
// Check to see if there's an identifiable tag in the end tag
if (truncatedEndTag.length > 0) {
// If so, find the start tag, and close it
var startTagExpr = new RegExp(
"<(" + truncatedEndTag + "\w?)(?:(?:\s\w+(?:=([\"\'])\w*\2)))*>");
var testString = truncated;
var startTagMatch = startTagExpr.exec(testString);
var startTag = null;
while (startTagMatch != null) {
startTag = startTagMatch[1];
testString = testString.replace(startTagExpr, '');
startTagMatch = startTagExpr.exec(testString);
}
if (startTag != null) {
truncated = truncated.replace(truncatedEndTagExpr, '</' + startTag + '>');
}
} else {
// Otherwise, cull off the broken end tag
truncated = truncated.replace(truncatedEndTagExpr, '');
}
}
// Now the tricky part. Reverse the text, and look for opening tags. For each opening tag,
// check to see that he closing tag before it is for that tag. If not, append a closing tag.
var testString = reverseHtml(truncated);
var reverseTagOpenExpr = /<(?:(["'])\w*=\w+ )*(\w*)>/;
var tagMatch = reverseTagOpenExpr.exec(testString);
while (tagMatch != null) {
var tag = tagMatch[0];
var tagName = tagMatch[2];
var startPos = tagMatch.index;
var endPos = startPos + tag.length;
var fragment = testString.substring(0, endPos);
// Test to see if an end tag is found in the fragment. If not, append one to the end
// of the truncated HTML, thus closing the last unclosed tag
if (!new RegExp("<" + tagName + "\/>").test(fragment)) {
truncated += '</' + reverseHtml(tagName) + '>';
}
// Get rid of the already tested fragment
testString = testString.replace(fragment, '');
// Get another tag to test
tagMatch = reverseTagOpenExpr.exec(testString);
}
return truncated;
}
function reverseHtml(str) {
var ph = String.fromCharCode(206);
var result = str.split('').reverse().join('');
while (result.indexOf('<') > -1) {
result = result.replace('<',ph);
}
while (result.indexOf('>') > -1) {
result = result.replace('>', '<');
}
while (result.indexOf(ph) > -1) {
result = result.replace(ph, '>');
}
return result;
}
回答by arendjr
I know this question is old, but I recently had the same problem. I wrote the following library, which truncates valid HTML safely: https://github.com/arendjr/text-clipper
我知道这个问题很老,但我最近遇到了同样的问题。我编写了以下库,它可以安全地截断有效的 HTML:https: //github.com/arendjr/text-clipper
回答by abidibo
There's a mootools plugin which does exactly what you need: mooReadAll at mootools forge
有一个 mootools 插件可以满足您的需求: mooReadAll at mootools forge
回答by Alec
If you want a light-weight solution in vanilla JS, this should do the trick, although it'll leave empty elements around, so it depends on if you care about those. Also note that it mutates the nodes in-place.
如果您想要在 vanilla JS 中使用轻量级解决方案,这应该可以解决问题,尽管它会留下空元素,所以这取决于您是否关心这些。另请注意,它会就地改变节点。
function truncateNode(node, limit) {
if (node.nodeType === Node.TEXT_NODE) {
node.textContent = node.textContent.substring(0, limit);
return limit - node.textContent.length;
}
node.childNodes.forEach((child) => {
limit = truncateNode(child, limit);
});
return limit;
}
const span = document.createElement('span');
span.innerHTML = '<b>foo</b><i>bar</i><u>baz</u>';
truncateNode(span, 5);
expect(span.outerHTML).toEqual('<span><b>foo</b><i>ba</i><u></u></span>');
回答by Seglinglin
None of the above solutions corresponded perfectly to my use case, so I created myself a small vanilla javascript function. It leaves empty elements but it could be corrected easily.
上述解决方案都没有完全符合我的用例,所以我为自己创建了一个小的 vanilla javascript 函数。它留下了空元素,但可以轻松更正。
const truncateWithHTML = (string, length) => {
// string = "<span class='className'>My long string that</span> I want shorter<span> but just a little bit</span>"
const noHTML = string.replace(/<[^>]*>/g, '');
// if the string does not need to be truncated
if (noHTML.length <= max){
return string;
}
// if the string does not contains tags
if (noHTML.length === string.length){
// add <span title=""> to allow complete string to appear on hover
return `<span title="${string}">${string.substring(0, max).trim()}…</span>`;
}
const substrings = string.split(/(<[^>]*>)/g).filter(Boolean);
// substrings = ["<span class='className'>","My long string that","</span>"," I want shorter","<span>"," but just a little bit","</span>"]
let count = 0;
let truncated = [];
for (let i = 0; i < substrings.length; i++) {
let substr = substrings[i];
// if the substring isn't an HTML tag
if (! substr.startsWith("<")){
if (count > length){
continue;
} else if (substr.length > (length-count-1)){
truncated.push(substr.substring(0, (length-count) - 1) + '…');
} else {
truncated.push(substr);
}
count += substr.length;
} else {
truncated.push(substr);
}
}
return `<span title="${noHTML}">${truncated.join("")}…</span>`;
}
Examples:
例子:
string = "<span class='className'>My long string that</span> I want shorter<span> but just a little bit</span>";
truncateWithHTML(string,10); // "<span title='My long string that I want shorter but just a little bit'><span class='className'>My long s…</span><span></span></span>"
truncateWithHTML(string,22); // "<span title='My long string that I want shorter but just a little bit'><span class='className'>My long string that</span> I…<span></span></span>"
回答by Malcolm
I just recently finished a jQuery function to do this using the width & height of the container. Test it out and see if it works for you. I'm not yet sure of all the compatibility issues, bugs, or limitations but I've tested it in FF, Chrome, and IE7.
我最近刚刚完成了一个 jQuery 函数来使用容器的宽度和高度来做到这一点。测试一下,看看它是否适合你。我还不确定所有的兼容性问题、错误或限制,但我已经在 FF、Chrome 和 IE7 中对其进行了测试。
回答by TK.
That's quite challenging.
这是相当有挑战性的。
If you don't have any HTML markup,the following might be useful.
如果您没有任何 HTML 标记,以下内容可能会有用。

