如何在Angular2中截断文本?

212

我能否限制字符串的长度,比如:我需要将标题长度限制为20个字符{{ data.title }}

是否有管道或过滤器可以限制长度?

13个回答

568

将文本截断为角括号的两种方法。

let str = 'How to truncate text in angular';

1. 解决方案

  {{str | slice:0:6}}

输出:

   how to

如果您想在切片字符串后附加任何文本,可以这样做:

   {{ (str.length>6)? (str | slice:0:6)+'...':(str) }}

输出:

 how to...

2. 解决方案(创建自定义管道)

如果您想要创建自定义截断管道

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
 name: 'truncate'
})

export class TruncatePipe implements PipeTransform {

transform(value: string, args: any[]): string {
    const limit = args.length > 0 ? parseInt(args[0], 10) : 20;
    const trail = args.length > 1 ? args[1] : '...';
    return value.length > limit ? value.substring(0, limit) + trail : value;
   }
}

在标记中

{{ str | truncate:[20] }} // or 
{{ str | truncate:[20, '...'] }} // or

不要忘记添加一个模块条目。

@NgModule({
  declarations: [
    TruncatePipe
  ]
})
export class AppModule {}

哪种解决方案性能更好,是方案1还是方案2?我认为方案1在性能方面更出色。 - Rigin Oommen
你可能需要在返回语句中添加一个空值检查,在我的情况下,我传递了一个空字符串,导致我的应用程序崩溃。return value && value.length > limit ? value.substring(0, limit) + trail : value; - Wildhammer
@ketan: 老师,我已经尝试了两种解决方案,它们都完美地运行了。但是我的情况有所不同,我们需要一开始只显示50个字符,然后在点击“阅读更多”链接后显示更多的文本。请告诉我这是否可行? - Kapil Soni
在解决方案2中,transform(value: string, args: string[]): string 应该改为 transform(value: string, args: any[]): string,因为管道的第一个参数是一个数字。 - MattOnyx
喜欢自定义的,这是我更好的(在我看来)实现:https://dev59.com/OVcP5IYBdhLWcg3wP36t#70189399 - Eugene P.
显示剩余2条评论

117

截断管道,带有可选的参数:

  • limit - 字符串最大长度
  • completeWords - 标记以最近完整单词截断,而不是字符
  • ellipsis - 添加的尾缀

-

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'truncate'
})
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit = 25, completeWords = false, ellipsis = '...') {
    if (completeWords) {
      limit = value.substr(0, limit).lastIndexOf(' ');
    }
    return value.length > limit ? value.substr(0, limit) + ellipsis : value;
  }
}

不要忘记添加模块条目。

@NgModule({
  declarations: [
    TruncatePipe
  ]
})
export class AppModule {}

用法

示例字符串:

public longStr = 'A really long string that needs to be truncated';

标记语言:

  <h1>{{longStr | truncate }}</h1> 
  <!-- Outputs: A really long string that... -->

  <h1>{{longStr | truncate : 12 }}</h1> 
  <!-- Outputs: A really lon... -->

  <h1>{{longStr | truncate : 12 : true }}</h1> 
  <!-- Outputs: A really... -->

  <h1>{{longStr | truncate : 12 : false : '***' }}</h1> 
  <!-- Outputs: A really lon*** -->

7
感谢提供管道,但是 limit = value.substr(0, 13).lastIndexOf(' '); 应该改为 limit = value.substr(0, limit).lastIndexOf(' '); - Tomnar
1
您还可以加入这样的代码: if (!value) { return ''; }if (value.length <= limit) { return value; } - Jarek Szczepański
2
为避免在不必要的值后添加省略号,请使用以下代码:if (value.length < limit) { return value; } else { return `${value.substr(0, limit)}${ellipsis}`; } - jabu.hlong
1
非常感谢,非常有帮助!但在两种情况下会失败:(a) 单词字符串(字符串中没有空格)和 (b) 超过限制的单词字符串。在这两种情况下都只返回“...”。 - philipp-fx
1
这仍然有效。可以用substring替换substr - BeardedPrince
显示剩余2条评论

28

您可以基于 CSS 截断文本。这有助于根据宽度而不是固定字符来截断文本。

示例

CSS


.truncate {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.content {
    width:100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

HTML

<div class="content">
    <span class="truncate">Lorem Ipsum is simply dummied text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</span>
</div>

注意:此代码仅适用于一行而不是多行。

如果您想要使用Angular实现,请使用Ketan的解决方案,这是最佳选择。


4
这个。就是这个! - Brugner
完美的无障碍性。 - Antonello Pasella

21

就像这样:

{{ data.title | slice:0:20 }}

如果你想要省略号,这里有一个解决方法

{{ data.title | slice:0:20 }}...

即使data.title没有被截断,这三个点号也不会出现吗? - Rohit Kumar
是的。此解决方案假定它将始终被截断。 - McCoy
如果此解决方案适用于所有文本截断或未截断的情况,则可以实现更通用的解决方案。 - Rohit Kumar
确认这在 Angular v11 中可以良好工作。 - Ali Celebi
6
一个可选的解决方案是在标题后面加上三个点 {{ data.title | slice:0:20 }}{{ data.title.length > 20 ? '...' : '' }} - sic-sic

8

基于单词限制长度

如果您想基于单词来截断文本,而不是字符,并且还想提供查看完整文本的选项,请尝试此方法。

如果您正在寻找基于单词的“阅读更多”解决方案,则可以使用下面的自定义管道。

管道:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'readMore'
})
export class ReadMorePipe implements PipeTransform {

  transform(text: any, length: number = 20, showAll: boolean = false, suffix: string = '...'): any {
    
    if (showAll) {
      return text;
    }

    if ( text.split(" ").length > length ) {
      
      return text.split(" ").splice(0, length).join(" ") + suffix;
    }

    return text;
  }

}

在模板中:

<p [innerHTML]="description | readMore:30:showAll"></p>
<button (click)="triggerReadMore()" *ngIf="!showAll">Read More<button>

组件:

export class ExamplePage implements OnInit {

    public showAll: any = false;
    
    triggerReadMore() {
        this.showAll = true;
    }
    
}

在模块中:

import { ReadMorePipe } from '../_helpers/read-more.pipe';

@NgModule({
  declarations: [ReadMorePipe]
})
export class ExamplePageModule {}

有什么想法可以让我在ngFor循环内运行它。当单击“阅读更多”时,似乎所有循环内容都会立即显示出来。 - Santosh
@Santosh,你可以尝试更新triggerReadMore()函数,通过使用父节点或兄弟节点关系来具体定位节点。 - Shahbaz A.
1
变量仍然是全局的,它不起作用。但是我创建了一个对象,并将每个ID与布尔值存储在其中。它起作用了。无论如何,感谢您的回复。 :) - Santosh
很高兴你解决了这个问题。不客气。 - Shahbaz A.

5

使用省略号截取字符串

无需额外的管道符,可以使用切片(slice)。

{{ stringText | slice: 0:25}} {{ stringText.length > 25 ? '...' : ''}}

5
非常简单,只需要使用切片管道(Angular的核心管道),就像你要求的那样,对于data.title进行操作:
{{ data.title | slice:0:20 }}

来自Angular常用文档 https://angular.io/api/common/SlicePipe


5

以下是使用一个接口来描述通过标记中的pipe传递的选项对象形状的替代方法。

@Pipe({
  name: 'textContentTruncate'
})
export class TextContentTruncatePipe implements PipeTransform {

  transform(textContent: string, options: TextTruncateOptions): string {
    if (textContent.length >= options.sliceEnd) {
      let truncatedText = textContent.slice(options.sliceStart, options.sliceEnd);
      if (options.prepend) { truncatedText = `${options.prepend}${truncatedText}`; }
      if (options.append) { truncatedText = `${truncatedText}${options.append}`; }
      return truncatedText;
    }
    return textContent;
  }

}

interface TextTruncateOptions {
  sliceStart: number;
  sliceEnd: number;
  prepend?: string;
  append?: string;
}

然后在你的标记中添加以下内容:
{{someText | textContentTruncate:{sliceStart: 0, sliceEnd: 50, append: '...'} }}

4

我一直在使用这个模块ng2 truncate,它非常简单,只需要导入模块就可以使用了……在{{ data.title | truncate : 20 }}中。


它已经移动到这里:https://www.npmjs.com/package/@yellowspot/ng-truncate - tibi
导入这个后我的测试失败了。 Jest 出现了一些奇怪的错误。 - tibi
@tibi 是什么样的错误?对我来说很简单,安装>在模块中导入>在其组件中使用。 - Kerim092

1
如果您想通过单词数量进行截断并添加省略号,可以使用此函数:
truncate(value: string, limit: number = 40, trail: String = '…'): string {
  let result = value || '';

  if (value) {
    const words = value.split(/\s+/);
    if (words.length > Math.abs(limit)) {
      if (limit < 0) {
        limit *= -1;
        result = trail + words.slice(words.length - limit, words.length).join(' ');
      } else {
        result = words.slice(0, limit).join(' ') + trail;
      }
    }
  }

  return result;
}

例子:

truncate('Bacon ipsum dolor amet sirloin tri-tip swine', 5, '…')
> "Bacon ipsum dolor amet sirloin…"

摘自: https://github.com/yellowspot/ng2-truncate/blob/master/src/truncate-words.pipe.ts

如果你想按字母数量截取,但不切割单词,请使用以下方法:

truncate(value: string, limit = 25, completeWords = true, ellipsis = '…') {
  let lastindex = limit;
  if (completeWords) {
    lastindex = value.substr(0, limit).lastIndexOf(' ');
  }
  return `${value.substr(0, limit)}${ellipsis}`;
}

例子:

truncate('Bacon ipsum dolor amet sirloin tri-tip swine', 19, true, '…')
> "Bacon ipsum dolor…"

truncate('Bacon ipsum dolor amet sirloin tri-tip swine', 19, false, '…')
> "Bacon ipsum dolor a…"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接