Кросс-браузерный многострочный переполнение текста с добавлением многоточия в пределах фиксированной ширины и высоты `<div>` - PullRequest
165 голосов
/ 04 августа 2010

Я сделал изображение для этого вопроса, чтобы его было легче понять.

Можно ли создать многоточие на <div> с фиксированной шириной и несколькими строками?

text-overflow

Я попробовал несколько плагинов jQuery тут и там, но не могу найти тот, который ищу.Любая рекомендация?Идеи?

Ответы [ 23 ]

0 голосов
/ 25 марта 2013

Очень простой функционал.

Директива:

  $scope.truncateAlbumName = function (name) {
    if (name.length > 36) {
      return name.slice(0, 34) + "..";
    } else {
      return name;
    }
  };

Вид:

<#p>{{truncateAlbumName(album.name)}}<#/p>
0 голосов
/ 13 декабря 2018

Я написал угловой компонент, который решает проблему. Он разбивает данный текст на элементы span. После рендеринга удаляет все переполненные элементы и помещает многоточие сразу после последнего видимого элемента.

Пример использования:

<app-text-overflow-ellipsis [text]="someText" style="max-height: 50px"></app-text-overflow-ellipsis>

Демонстрация Stackblitz: https://stackblitz.com/edit/angular-wfdqtd

Компонент:

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef, HostListener,
  Input,
  OnChanges,
  ViewChild
} from '@angular/core';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-text-overflow-ellipsis',
  template: `
    <span *ngFor="let word of words; let i = index" [innerHTML]="word + (!endsWithHyphen(i) ? ' ' : '')"></span>
    <span #ellipsis [hidden]="!showEllipsis && !initializing" [class.initializing]="initializing" [innerHTML]="'...' + (initializing ? '&nbsp;' : '')"></span>
  `,
  styles: [`
    :host {
      display: block; 
      position: relative;
    }
    .initializing {
      opacity: 0;
    }
  `
  ]
})

export class TextOverflowEllipsisComponent implements OnChanges {
  @Input()
  text: string;

  showEllipsis: boolean;
  initializing: boolean;

  words: string[];

  @ViewChild('ellipsis')
  ellipsisElement: ElementRef;

  constructor(private element: ElementRef, private cdRef: ChangeDetectorRef) {}

  ngOnChanges(){
    this.init();
  }

  @HostListener('window:resize')
  init(){
    // add space after hyphens
    let text = this.text.replace(/-/g, '- ') ;

    this.words = text.split(' ');
    this.initializing = true;
    this.showEllipsis = false;
    this.cdRef.detectChanges();

    setTimeout(() => {
      this.initializing = false;
      let containerElement = this.element.nativeElement;
      let containerWidth = containerElement.clientWidth;
      let wordElements = (<HTMLElement[]>Array.from(containerElement.childNodes)).filter((element) =>
        element.getBoundingClientRect && element !== this.ellipsisElement.nativeElement
      );
      let lines = this.getLines(wordElements, containerWidth);
      let indexOfLastLine = lines.length - 1;
      let lineHeight = this.deductLineHeight(lines);
      if (!lineHeight) {
        return;
      }
      let indexOfLastVisibleLine = Math.floor(containerElement.clientHeight / lineHeight) - 1;

      if (indexOfLastVisibleLine < indexOfLastLine) {

        // remove overflowing lines
        for (let i = indexOfLastLine; i > indexOfLastVisibleLine; i--) {
          for (let j = 0; j < lines[i].length; j++) {
            this.words.splice(-1, 1);
          }
        }

        // make ellipsis fit into last visible line
        let lastVisibleLine = lines[indexOfLastVisibleLine];
        let indexOfLastWord = lastVisibleLine.length - 1;
        let lastVisibleLineWidth = lastVisibleLine.map(
          (element) => element.getBoundingClientRect().width
        ).reduce(
          (width, sum) => width + sum, 0
        );
        let ellipsisWidth = this.ellipsisElement.nativeElement.getBoundingClientRect().width;
        for (let i = indexOfLastWord; lastVisibleLineWidth + ellipsisWidth >= containerWidth; i--) {
          let wordWidth = lastVisibleLine[i].getBoundingClientRect().width;
          lastVisibleLineWidth -= wordWidth;
          this.words.splice(-1, 1);
        }


        this.showEllipsis = true;
      }
      this.cdRef.detectChanges();

      // delay is to prevent from font loading issues
    }, 1000);

  }

  deductLineHeight(lines: HTMLElement[][]): number {
    try {
      let rect0 = lines[0][0].getBoundingClientRect();
      let y0 = rect0['y'] || rect0['top'] || 0;
      let rect1 = lines[1][0].getBoundingClientRect();
      let y1 = rect1['y'] || rect1['top'] || 0;
      let lineHeight = y1 - y0;
      if (lineHeight > 0){
        return lineHeight;
      }
    } catch (e) {}

    return null;
  }

  getLines(nodes: HTMLElement[], clientWidth: number): HTMLElement[][] {
    let lines = [];
    let currentLine = [];
    let currentLineWidth = 0;

    nodes.forEach((node) => {
      if (!node.getBoundingClientRect){
        return;
      }

      let nodeWidth = node.getBoundingClientRect().width;
      if (currentLineWidth + nodeWidth > clientWidth){
        lines.push(currentLine);
        currentLine = [];
        currentLineWidth = 0;
      }
      currentLine.push(node);
      currentLineWidth += nodeWidth;
    });
    lines.push(currentLine);

    return lines;
  }

  endsWithHyphen(index: number): boolean {
    let length = this.words[index].length;
    return this.words[index][length - 1] === '-' && this.words[index + 1] && this.words[index + 1][0];
  }
}
0 голосов
/ 08 августа 2010

не уверен, что это то, что вы ищете, он использует минимальную высоту вместо высоты.

    <div id="content" style="min-height:10px;width:190px;background:lightblue;">
    <?php 
        function truncate($text,$numb) {
            // source: www.kigoobe.com, please keep this if you are using the function
            $text = html_entity_decode($text, ENT_QUOTES);
            if (strlen($text) > $numb) {
                $text = substr($text, 0, $numb);
                $etc = "..."; 
                $text = $text.$etc;
            } 
            $text = htmlentities($text, ENT_QUOTES);
            return $text;
        }
        echo truncate("this is a multi-lines text block, some lines inside the div, while some outside", 63);
    ?>
    </div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...