【问题标题】:How to truncate text with jQuery but keep the HTML formatting?如何使用 jQuery 截断文本但保留 HTML 格式?
【发布时间】:2015-06-03 03:31:50
【问题描述】:

如何使用 jQuery 截断文本但保留 HTML? 尝试使用以下代码,但不幸的是没有返回 HTML 格式。

var truncate = function() {
  $('p.truncated').text(function(index, oldText) {
    if (oldText.length > 20) {
      return '...' + oldText.substr(-25);
    }
    return oldText;
  });
}

如果你运行 sn-p,你会看到我在寻找什么。

var truncate = function() {
  $('p.truncated').text(function(index, oldText) {
    if (oldText.length > 20) {
      return '...' + oldText.substr(-25);
    }
    return oldText;
  });
}

truncate();




var truncate2 = function() {
  $("p.truncated2").each(function() {
    //var theContent = $(this).text();
    var theContent = $(this).html();
    var n = theContent.substr(-25);
    $(this).html( '...' +n );
  });

}

truncate2();
p {
  margin: 0 0 30px 0;
  display: block;
  padding: 5px;
}
streak {
  color: green;
}
double {
  color: orange;
}
p span {
  color: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
How to make something like this...
<p class="sheet">
  <streak>start</streak>
  <streak>1</streak>
  <streak>2</streak>
  <double>3</double>
  <double>4</double>
  <span>5</span>
  <span>6</span>
  <streak>7</streak>
  <streak>8</streak>
  <double>9</double>
  <double>10</double>
  <streak>end</streak>
</p>
...becomes something like this with jquery?
<p>
  ...
  <span>6</span>
  <streak>7</streak>
  <streak>8</streak>
  <double>9</double>
  <double>10</double>
  <streak>end</streak>
</p>
<hr />Here is a try with jquery but it return text without html elements.
<p class="truncated">
  <streak>start</streak>
  <streak>1</streak>
  <streak>2</streak>
  <double>3</double>
  <double>4</double>
  <span>5</span>
  <span>6</span>
  <streak>7</streak>
  <streak>8</streak>
  <double>9</double>
  <double>10</double>
  <streak>end</streak>
</p>
The second try
<p class="truncated2">
  <streak>start</streak>
  <streak>1</streak>
  <streak>2</streak>
  <double>3</double>
  <double>4</double>
  <span>5</span>
  <span>6</span>
  <streak>7</streak>
  <streak>8</streak>
  <double>9</double>
  <double>10</double>
  <streak>end</streak>
</p>
How can I keep html elements?

【问题讨论】:

    标签: javascript jquery html truncate


    【解决方案1】:

    如果你想继续计算字符数,你也可以使用range 对象。您设置要删除的范围,它也会删除节点。所以你操作文本但你保留html标签。

    var truncate = function() {
      var range_all = document.createRange();
      range_all.selectNodeContents(document.getElementsByClassName('truncated')[0]);
      if (range_all.endOffset > 20) {
        range_all.setEnd(document.getElementsByClassName('truncated')[0], range_all.endOffset - 12);
        range_all.deleteContents();
        $('p.truncated').html('... ' + $('p.truncated').html());
      }
    
    }
    
    truncate();
    
    
    
    
    var truncate2 = function() {
      $("p.truncated2").each(function() {
        //var theContent = $(this).text();
        var theContent = $(this).html();
        var n = theContent.substr(-25);
        $(this).html('...' + n);
      });
    
    }
    
    truncate2();
    p {
      margin: 0 0 30px 0;
      display: block;
      padding: 5px;
    }
    streak {
      color: green;
    }
    double {
      color: orange;
    }
    p span {
      color: grey;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    How to make something like this...
    <p class="sheet">
      <streak>start</streak>
      <streak>1</streak>
      <streak>2</streak>
      <double>3</double>
      <double>4</double>
      <span>5</span>
      <span>6</span>
      <streak>7</streak>
      <streak>8</streak>
      <double>9</double>
      <double>10</double>
      <streak>end</streak>
    </p>
    ...becomes something like this with jquery?
    <p>
      ...
      <span>6</span>
      <streak>7</streak>
      <streak>8</streak>
      <double>9</double>
      <double>10</double>
      <streak>end</streak>
    </p>
    <hr />If text is longer than 25 character, select until 12th and delete selection. Then add '...' at the beginning.
    <p class="truncated">
      <streak>start</streak>
      <streak>1</streak>
      <streak>2</streak>
      <double>3</double>
      <double>4</double>
      <span>5</span>
      <span>6</span>
      <streak>7</streak>
      <streak>8</streak>
      <double>9</double>
      <double>10</double>
      <streak>end</streak>
    </p>
    The second try
    <p class="truncated2">
      <streak>start</streak>
      <streak>1</streak>
      <streak>2</streak>
      <double>3</double>
      <double>4</double>
      <span>5</span>
      <span>6</span>
      <streak>7</streak>
      <streak>8</streak>
      <double>9</double>
      <double>10</double>
      <streak>end</streak>
    </p>
    How can I keep html elements?

    【讨论】:

      【解决方案2】:

      对于任何 CMS 或博客来说,这是一个典型的困境,其中预告片应该呈现文章的开头:通常解决方案是从其标签中删除文本并以精确的计数剪切,或者保留标签但近似剪切,因为标签也算...

      这是我对满足这两种需求的方法的建议(保持标签并按准确数量切割):

      function cutKeepingTags(elem, count) {
        var matches = $(elem).html().match(/([^<])*(<.*>)?(.*)/),
          // To be more clear, let's "rename" what we get:
          textBefore = matches[1] || '',
          children = matches[2] || '',
          textAfter = matches[3] || '';
        if (textBefore.length <= count) {
          // cool, already that's end!
          return textBefore.substr(count);
        }
        if ($(elem).text().length == textBefore.length + textAfter.length) {
          /* (remember that .text() returns the concatenation of all text nodes found
             deeply in the element)
             If equal there is no child (or there are children but no text in them),
             so we can simply keep children and text enough after children:
          */
          return textBefore + chidren + textAfter.substr(count - textBefore.length);
        }
        // Otherwise we must loop through children to get more text:
        var grabText = textBefore;
        $(elem).children().each(function() {
          // Get text from current child:
          grabText += cutKeepingTags(this, count - grabText.length);
          if (grabText.length == count) {
            // We already got text enough:
            return grabText;
          }
        });
        // No more child and count not reached, return what we got.
        return grabText;
      }
      

      未测试!


      编辑:
      终于得到了一个实用的解决方案:你找到它here on Code Review

      【讨论】:

        【解决方案3】:

        您需要先拆分子元素。

        var truncate = function() {
          var $elem = $('p.truncated');
          var html = $elem.html().split(/>\s*</);
          
          if(html.length > 5)
            html = "... <" + html.slice(-6).join('> <');
          
          $elem.html(html);
        }
        truncate();
        p {
          margin: 0 0 30px 0;
          display: block;
          padding: 5px;
        }
        streak {
          color: green;
        }
        double {
          color: orange;
        }
        p span {
          color: grey;
        }
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <p class="truncated">
          <streak>start</streak>
          <streak>1</streak>
          <streak>2</streak>
          <double>3</double>
          <double>4</double>
          <span>5</span>
          <span>6</span>
          <streak>7</streak>
          <streak>8</streak>
          <double>9</double>
          <double>10</double>
          <streak>end</streak>
        </p>

        【讨论】:

        • 感谢 Samuel,如果长度值较高,则失败。例如,如果我将 6 更改为 12。 if(html.length > 12); html = "...
        • 好的,IF 条件缺少{}
        • 可能是格式错误,因为这里的 IF 条件没有作用。
        【解决方案4】:

        伙计,换掉你的

        var theContent = $(this).html();
        

        var theContent = $(this).outerHTML();
        

        【讨论】:

        • 人们何时投票?你能留言说明原因吗?
        【解决方案5】:

        我已经根据上面发布的代码完成了自己的纯 JS(实际上是 TypeScript)实现。它使用不同的方法来提取父级的 html,并具有额外的功能来修剪提供的 html 开头的空格,如果文本被截断,则始终修剪最后的空格

        /**
         * recursively looks through all the text nodes until the text size exceeds the limit
         * in that case will trim the html preserving all the existing tags
         * @param element html element to be processed
         * @param maxLength max amount of text symbols to be present
         * @param shouldTrimStart set to false to preserve whitespace at the beginning of the projected content.
         */
        function truncateHTML<T extends ChildNode>(element?: T, maxLength = 0, shouldTrimStart = true) {
          let truncatedHTML = '';
          let innerTextLength = 0;
          const nodes = Array.from(element?.childNodes ?? []);
          for (let index = 0; index < nodes.length; index++) {
            const node = nodes[index];
            switch (node.nodeType) {
              case Node.TEXT_NODE: {
                let content = (node.nodeValue ?? '').substr(0, maxLength - innerTextLength);
                if (shouldTrimStart) {
                  content = content.trimLeft();
                  if (content) {
                    shouldTrimStart = false;
                  }
                }
                truncatedHTML += content;
                innerTextLength += content.length;
                break;
              }
              case Node.ELEMENT_NODE: {
                const childPart = truncateHTML(node, maxLength - innerTextLength, shouldTrimStart);
                const clone = node.cloneNode(true) as Element;
                if (innerTextLength + childPart.innerTextLength === maxLength && index === nodes.length - 1) {
                  // removing trailing spaces in the end of the last word
                  childPart.truncatedHTML = childPart.truncatedHTML.trimRight();
                }
                clone.innerHTML = childPart.truncatedHTML;
                truncatedHTML += clone.outerHTML;
                innerTextLength += childPart.innerTextLength;
                shouldTrimStart = childPart.shouldTrimStart;
                break;
              }
              default:
                console.error(new Error(`Unexpected node type: ${node.nodeType}`));
            }
            if (innerTextLength === maxLength) {
              break;
            }
          }
          return { truncatedHTML, innerTextLength, shouldTrimStart };
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-05-15
          • 1970-01-01
          • 1970-01-01
          • 2016-12-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多