利用angular指令和网格布局实现上面是图片,下面是标题的通用布局

139 阅读2分钟

指令可以理解为没有模版的组件,它需要一个宿主元素,如果使用方括号 [] 指定 Selector,该指令就变成一个属性型指令,angular除了属性型指令,还有结构型指令如ngIf等,,本文暂时先实现一个属性型指令。

// grid-item.directive.ts 网格布局中的一个网格单元
import { Directive, HostBinding } from '@angular/core';

@Directive({
  selector: '[appGridItem]'
})
export class GridItemDirective {

  // HostBinding进行属性绑定
  // 该方法进行绑定后,直接将指令selector写在宿主元素上就可以自动设置为以下样式
  @HostBinding('style.display') display = 'grid';
  
  // grid-template-areas用于给网格的各个区域命名,如下意味着一个网格单元中有两个元素,一个元素的名字叫‘image’,一个元素的名字叫‘title’,名称可以随便起,该属性值与网格内元素的‘grid-area’属性值对应
  @HostBinding('style.grid-template-areas') template = `'image' 'title'`;
  
  // place-items是‘justify- items’和‘align-items’的简写形式
  @HostBinding('style.place-items') align = 'center';
  
  @HostBinding('style.width') width = '4rem';
}
// grid-item-image.directive.ts 网格单元中的图像部分
import {
  Directive,
  OnInit,
  Input,
  ElementRef,
  Renderer2,
  HostListener
} from '@angular/core';

@Directive({
  selector: '[appGridItemImage]'
})
export class GridItemImageDirective implements OnInit {

  // 将指令的属性名与指令的selector一致,在使用该指令时可以直接用一次该属性名并传值的同时调用指令,并给某些属性赋值
  @Input() appGridItemImage = '2rem';
  constructor(private elr: ElementRef, private renderer: Renderer2) {}

  // 指令也有生命周期,但是不如组件生命周期那么多
  // 在ngOninit中,类属性已经设置完毕,所以在ngOninit中可以安全使用类中的属性
  ngOnInit(): void {
  
    // 设置了该属性,就在网格结构对应‘image’的位置占了位置,元素渲染时就渲染在对应的位置
    this.setStyle('grid-area', 'image');
    
    this.setStyle('width', this.appGridItemImage);
    this.setStyle('height', this.appGridItemImage);
    this.setStyle('object-fit', 'cover');
  }

  private setStyle(styleName: string, styleValue: string | number) {
  
    // angular指令中属性的绑定有两种方法:HostBinding和Renderer2设置样式
    this.renderer.setStyle(this.elr.nativeElement, styleName, styleValue);
  }
  
  // 指令的事件绑定,第一个参数是事件类型,第二个参数是事件接收的参数,并且事件的绑定要有监听到事件后调用的函数的方法的声明,声明的方法中接受事件触发元素的参数
  @HostListener('click', ['$event.target'])
  handleClick(ev) {
    console.log(ev);
  }
}
// grid-item-title.directive.ts 网格单元中的标题部分
import { Directive, Input, HostBinding } from '@angular/core';

@Directive({
  selector: '[appGridItemTitle]'
})
export class GridItemTitleDirective {

  // 一个属性可以同时使用多个注解进行约束
  @HostBinding('style.font-size') @Input() appGridItemTitle = '0.5rem';
  
  // 设置了该属性,就在网格结构对应‘title’的位置占了位置,元素渲染时就渲染在对应的位置
  @HostBinding('style.grid-area') area = 'title';
  @HostBinding('style.white-space') wrap = 'nowrap';
}
// test.component.html 指令的使用
<div appGridItem *ngFor="let item of items">
	<img  appGridItemImage="'4rem'" src="item.imgUrl" alt="">
	<span appGridItemTitle="'2rem'">{{item.title}}</span>
</div>