使用angular写一个关于文字溢出的奇葩指令

之前有个类似关于文字溢出的需求,但是又略有不同。具体需求如下图所示

要求使用angular

当文字超过指定的长度时会出现省略号加上More

当点击More的时候就显示全部的内容,点击Show less的时候就返回到第一张图所示

由于项目使用的是angular框架,所以就把这个小功能写成了directive,代码有点多,但是我会加上相关的注释,这样会清晰一点

首先介绍一下在HTML中的用法

textCut是这个指令的名字,传入的数值是你希望要从第几个数值截取,比如这个是从第25个截取
<p class="mb-2" textCut="25">Job posting templates allow you to save content and xxxxxxxxxxx 
 </p>
复制代码
这个是完整的指令的封装
import { Directive, ElementRef, HostListener, Input, AfterViewInit, Renderer2 } from '@angular/core';

@Directive({
  selector: '[textCut]'
})
export class TextCutDirective implements AfterViewInit {
  @Input('textCut') textCutSize: number; //这个就是从HTML中传入的截取文字的个数

  private allContent: string; //这个变量代表标签中原本的所有的文字,比如这里的P标签
  private contentEle: HTMLSpanElement;
  private linkEle: HTMLSpanElement;
  private isExpanded: boolean; //是否展开已经缩起来的文字

  constructor(private el: ElementRef, private renderer: Renderer2) {
  }

  ngAfterViewInit() {//这个生命周期是说页面元素可以获取到的时候
  this.waitUntilAddedToDom().then(() => {
    if (this.shouldCollapse()) { // 如果需要折叠起来 就走这个逻辑
      this.isExpanded = false;
      this.allContent = this.el.nativeElement.innerText; //因为折叠会改变p标签的dom结构【this.el.nativeElement代表使用这个指令的元素,比如HTML中的p标签】,所以暂时把之前的内容存起来以备后边使用
      this.collapseContent(); //折叠的主要逻辑
    }
  })
  }

  private expandContent() { // 点击...more会触发的事件
    this.contentEle = this.getContentEle(this.allContent);
    this.linkEle = this.getLinkEle('Show Less');
    this.refreshContent();
  }

  private collapseContent() {// 点击Show less会触发的事件
    this.contentEle = this.getContentEle(this.getContentCollapsed(this.allContent, this.textCutSize));
    this.linkEle = this.getLinkEle('More');
    this.refreshContent();
  }

//这个方法是用来重新渲染P标签的DOM结构,让两个span标签去显示p里边的内容
  private refreshContent() {
    this.el.nativeElement.innerText = '';
    this.renderer.appendChild(this.el.nativeElement, this.contentEle);
    this.renderer.appendChild(this.el.nativeElement, this.linkEle);
  }

//这个方法是用来动态生成一个新的span标签,并将相关的字符内容放进去
  private getContentEle(contentDisplayed: string) { 
    let content: HTMLSpanElement;
    content = this.renderer.createElement('span')
    content.innerText = contentDisplayed;
    return content;
  }

//这个也是动态生成一个span标签用来放到上一个span的后边 【就是用来放More或者Show less】
  private getLinkEle(text: string) {
    let link: HTMLSpanElement;
    link = this.renderer.createElement('span')
    link.innerText = ' ' + text;
    this.setLinkEleStyle(link);
    this.addClickListenerToLinkEle(link);
    return link;
  }

//这个方法用来控制点击Show less和More的逻辑
  private addClickListenerToLinkEle(link: HTMLSpanElement) {
    this.renderer.listen(link, 'click', () => {
      this.isExpanded = !this.isExpanded;
      if (this.isExpanded) {
        this.expandContent();
      } else {
        this.collapseContent()
      }
    });
  }

//用来设置More,Show less的样式
  private setLinkEleStyle(link: HTMLSpanElement) {
    this.renderer.setStyle(link, 'color', '#287AB9');
    this.renderer.setStyle(link, 'cursor', 'pointer');
  }

//这个是文字会溢出的条件,就是文字超过两行的时候才可以会出现我们规定的显示...More
  private shouldCollapse() {
    const MAX_HEIGHT = 38;
    return this.el.nativeElement.offsetHeight > MAX_HEIGHT;
  }
  
//这是后来发现的一个bug 由于angular莫名的加载顺序,导致我们的元素并没有加载到DOM树里去 所以就这个方法去解决这个问题
  private waitUntilAddedToDom(timeout = 1000): Promise<void> {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const timer = setInterval(() => {
        const elementAddedToDom = document.body.contains(this.el.nativeElement);

        if (elementAddedToDom) {
          clearInterval(timer);
          return resolve();
        }

        if (Date.now() - startTime >= timeout) {
          clearInterval(timer);
          return reject('timeout');
        }
      }, 100);
    });
  }

//这个方法主要是截取相关的字符并加上...
  private getContentCollapsed(content: string, truncatedSize: number): string {
    return content.split(' ')
      .slice(0, truncatedSize)
      .join(' ')
      .concat(' ...');
  }
}

复制代码
从这个小例子中,可以学习到很多angular是怎样去操作一些DOM元素,包括创建,添加元素,设置元素样式,监听事件等等。希望你可以从中学习到新的知识。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值