Angular学习之以Tooltip为例了解自定义指令

 3810

本篇文章带大家继续angular的学习,以Tooltip为例来了解一下自定义指令,希望对大家有所帮助!


Angular学习之以Tooltip为例了解自定义指令


在之前的文章中,我们已经概览了 Angular 的相关内容。在自定义指令的部分,我们已经能够实现编写,但是,在实际场景中,我们还需要标准化的管理。

Angular 是 Angular.js 的升版。

So,本文,我们就以 Tooltip 来讲解下自定义指令的内容。

线上效果图,如下:

Angular学习之以Tooltip为例了解自定义指令

目录结构

在上一篇文章的实现的代码项目基础上,执行命令行:

  1. # 进入 directives 文件夹
  2. $ cd directives
  3.  
  4. # 创建 tooltip 文件夹
  5. $ mkdir tooltip
  6.  
  7. # 进入 tooltip 文件夹
  8. $ cd tooltip
  9.  
  10. # 创建 tooltip 组件
  11. $ ng generate component tooltip
  12.  
  13. # 创建 tooltip 指令
  14. $ ng generate directive tooltip

执行完上面的命令行之后,你会得到 app/directive/tooltip 的文件目录结构如下:

  1. tooltip
  2. ├── tooltip                                           // tooltip 组件
  3. │    ├── user-list.component.html                     // 页面骨架
  4. │    ├── user-list.component.scss                     // 页面独有样式
  5. │    ├── user-list.component.spec.ts                  // 测试文件
  6. │    └── user-list.component.ts                       // javascript 文件
  7. ├── tooltip.directive.spec.ts                         // 测试文件
  8. └── tooltip.directive.ts                              // 指令文件

嗯,这里我将组件放在 tooltip 的同级,主要是方便管理。当然,这个因人而异,你可以放在公共组件 components 文件夹内。


编写 tooltip 组件

在 html 文件中,有:

  1. <div class="caret"></div>
  2. <div class="tooltip-content">{{data.content}}</div>

在样式文件 .scss 中,有:

  1. $black: #000000;
  2. $white: #ffffff;
  3. $caret-size: 6px;
  4. $tooltip-bg: transparentize($black, 0.25); // transparentize 是 sass 的语法
  5. $grid-gutter-width: 30px;
  6. $body-bg-color: $white;
  7. $app-anim-time: 200ms;
  8. $app-anim-curve: ease-out;
  9. $std-border-radius: 5px;
  10. $zindex-max: 100;
  11.  
  12. // :host 伪类选择器,给组件元素本身设置样式
  13. :host {
  14.   position: fixed;
  15.   padding: $grid-gutter-width/3 $grid-gutter-width/2;
  16.   background-color: $tooltip-bg;
  17.   color: $body-bg-color;
  18.   opacity: 0;
  19.   transition: all $app-anim-time $app-anim-curve;
  20.   text-align: center;
  21.   border-radius: $std-border-radius;
  22.   z-index: $zindex-max;
  23. }
  24.  
  25. .caret { // 脱字符
  26.   width: 0;
  27.   height: 0;
  28.   border-left: 6px solid transparent;
  29.   border-right: 6px solid transparent;
  30.   border-bottom: 6px solid $tooltip-bg;
  31.   position: absolute;
  32.   top: -$caret-size;
  33.   left: 50%;
  34.   margin-left: -$caret-size/2;
  35.   border-bottom-color: $tooltip-bg;
  36. }

嗯~,css 是一个神奇的东西,之后会安排一篇文章来讲解下 sass 相关的内容...


然后,在 javascript 文件 tooltip.component.ts 内容如下:

  1. import { 
  2.   Component, 
  3.   ElementRef, // 元素指向
  4.   HostBinding, 
  5.   OnDestroy, 
  6.   OnInit 
  7. } from '@angular/core';
  8.  
  9. @Component({
  10.   selector: 'app-tooltip', // 标识符,表明我这个组件叫做啥,这里是 app-tooltip
  11.   templateUrl: './tooltip.component.html', // 本组件的骨架
  12.   styleUrls: ['./tooltip.component.scss'] // 本组件的私有样式
  13. })
  14. export class TooltipComponent implements OnInit {
  15.  
  16.   public data: any; // 在 directive 上赋值
  17.   private displayTimeOut:any;
  18.  
  19.   // 组件本身 host 绑定相关的装饰器
  20.   @HostBinding('style.top')  hostStyleTop!: string;
  21.   @HostBinding('style.left') hostStyleLeft!: string;
  22.   @HostBinding('style.opacity') hostStyleOpacity!: string;
  23.  
  24.   constructor(
  25.     private elementRef: ElementRef
  26.   ) { }
  27.  
  28.   ngOnInit(): void {
  29.     this.hostStyleTop = this.data.elementPosition.bottom + 'px';
  30.  
  31.     if(this.displayTimeOut) {
  32.       clearTimeout(this.displayTimeOut)
  33.     }
  34.  
  35.     this.displayTimeOut = setTimeout((_: any) => {
  36.       // 这里计算 tooltip 距离左侧的距离,这里计算公式是:tooltip.left + 目标元素的.width - (tooltip.width/2)
  37.       this.hostStyleLeft = this.data.elementPosition.left + this.data.element.clientWidth / 2 - this.elementRef.nativeElement.clientWidth / 2 + 'px'
  38.       this.hostStyleOpacity = '1';
  39.       this.hostStyleTop = this.data.elementPosition.bottom + 10 + 'px'
  40.     }, 500)
  41.   }
  42.    
  43.    
  44.   // 组件销毁
  45.   ngOnDestroy() {
  46.     // 组件销毁后,清除定时器,防止内存泄露
  47.     if(this.displayTimeOut) {
  48.       clearTimeout(this.displayTimeOut)
  49.     }
  50.   }
  51. }


编写 tooltip 指令

这是本文的重点,具体的说明,我在代码上标注出来~

相关的文件 tooltip.directive.ts 内容如下:

  1. import { 
  2.   ApplicationRef, // 全局性调用检测
  3.   ComponentFactoryResolver, // 创建组件对象
  4.   ComponentRef, // 组件实例的关联和指引,指向 ComponentFactory 创建的元素
  5.   Directive, ElementRef, 
  6.   EmbeddedViewRef, // EmbeddedViewRef 继承于 ViewRef,用于表示模板元素中定义的 UI 元素。
  7.   HostListener, // DOM 事件监听
  8.   Injector, // 依赖注入
  9.   Input 
  10. } from '@angular/core';
  11.  
  12. import { TooltipComponent } from './tooltip/tooltip.component';
  13.  
  14. @Directive({
  15.   selector: '[appTooltip]'
  16. })
  17. export class TooltipDirective {
  18.   @Input("appTooltip") appTooltip!: string;
  19.  
  20.   private componentRef!: ComponentRef<TooltipComponent>;
  21.  
  22.   // 获取目标元素的相关位置,比如 left, right, top, bottom
  23.   get elementPosition() {
  24.     return this.elementRef.nativeElement.getBoundingClientRect(); 
  25.   }
  26.  
  27.   constructor(
  28.     protected elementRef: ElementRef,
  29.     protected appRef: ApplicationRef,
  30.     protected componentFactoryResolver: ComponentFactoryResolver,
  31.     protected injector: Injector
  32.   ) { }
  33.  
  34.   // 创建 tooltip
  35.   protected createTooltip() {
  36.     this.componentRef = this.componentFactoryResolver
  37.       .resolveComponentFactory(TooltipComponent) // 绑定 tooltip 组件
  38.       .create(this.injector);
  39.  
  40.     this.componentRef.instance.data = { // 绑定 data 数据
  41.       content: this.appTooltip,
  42.       element: this.elementRef.nativeElement,
  43.       elementPosition: this.elementPosition
  44.     }
  45.  
  46.     this.appRef.attachView(this.componentRef.hostView); // 添加视图
  47.     const domElem = (this.componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
  48.     document.body.appendChild(domElem);
  49.   }
  50.    
  51.   // 删除 tooltip
  52.   protected destroyTooltip() {
  53.     if(this.componentRef) {
  54.       this.appRef.detachView(this.componentRef.hostView); // 移除视图
  55.       this.componentRef.destroy();
  56.     }
  57.   }
  58.    
  59.   // 监听鼠标移入
  60.   @HostListener('mouseover')
  61.   OnEnter() {
  62.     this.createTooltip();
  63.   }
  64.      
  65.   // 监听鼠标移出
  66.   @HostListener('mouseout')
  67.   OnOut() {
  68.     this.destroyTooltip();
  69.   }
  70.  
  71. }

到这里,已经完成了 99% 的功能了,下面我们在页面上调用即可。


页面上调用

我们在 user-list.component.html 上添加下面的内容:

  1. <p style="margin-top: 100px;">
  2.   <!-- [appTooltip]="'Hello Jimmy'" 是重点 -->
  3.   <span 
  4.     [appTooltip]="'Hello Jimmy'"
  5.     style="margin-left: 200px; width: 160px; text-align: center; padding: 20px 0; display: inline-block; border: 1px solid #999;"
  6.   >Jimmy</span>
  7. </p>

TooltipDirective 这个指令我们已经在 app.module.ts 上进行声明,我们直接调用即可。目前的效果如下:


Angular学习之以Tooltip为例了解自定义指令

我们实现的 tooltip 是底部居中展示,也就是我们平常使用框架,比如 angular ant design 中 tooltip 的 bottom 属性。对于其他属性,读者感兴趣的话,可以进行扩展。

至此,我们可以很好的维护自己编写的指令文件了。


本文网址:https://www.zztuku.com/detail-11578.html
站长图库 - Angular学习之以Tooltip为例了解自定义指令
申明:本文转载于《掘金社区》,如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐