Angular学习笔记二之组件模版与指令Directive

一、组件模版

(一)数据绑定

  1. 用法
    根据数据渲染模版内容

    <h1>{{message}}</h1>
    <h1>{{getInformation()}}</h1>
    <h1>{{a == b ? 'true' : 'false'}}</h1>
    <h1>{{'字符串'}}</h1>
    <h1 [innerHTML]="content"></h1> 
    
  2. 容错处理
    当模版使用的数据层级比较深的时候,如果某一层是可选的,这是就需要做容错处理。
    组件类中:
    Person类的task属性是可选的

    interface Person {
        name: string;
        age: number;
        task?: Task;
    }
    interface Task {
        name: string;
    }
    @Component({
      selector: 'app-layout',
      templateUrl: './layout.component.html',
    })
    
    export class LayoutComponent {
      public zs:Person = {
        name: 'zs',
        age: 18
      }
    }
    

    组件模版中:

    • 使用*ngIf判断task属性是否存在,如果不存在不会渲染这个h1标签
    • 使用安全操作符,如果不存在会有一个空的h1标签
    <h1>{{zs.name}}</h1>
    <h1 *ngIf="zs.task">{{zs.task.name}}</h1>
    <h1>{{zs.task?.name}}</h1>
    

(二)属性绑定

  1. 普通属性绑定
    • 给DOM对象绑定
    <h1 [innerHTML]="content"></h1> 
    
    • 给html标记绑定。自定义属性
    <h1 [attr.data-test]="a">omg</h1>
    
  2. 类名绑定
    • 可以根据数据一次设定一个,也可以批量设定
    <h1 [class.active]="active">hhhhh</h1>
    <h1 [ngClass]="{'active':active,'error':error}">lllll</h1>
    
  3. 样式绑定
    • 可以通过[style.属性名]加上具体的属性,也可以属性绑定一个数据源中的对象
    <h1 [style.color]="active?'red':'blue'">style</h1>
    <h1 [ngStyle]="styleObj">stylesadasdsd</h1>
    

(三)事件绑定

<button (click)="handleClick($event)">按钮</button>
<!--使用事件修饰符-->
<input (keyup.enter)="enter()">

(四)获取原生DOM对象

  1. 在组件模版中获取,使用#标识元素,并且传递到函数中
    <button (click)="handleClick(btn)" #btn>按钮</button>
    
  2. 使用ViewChild获取一个元素
  • 组件模版:

    <p #myP>hello</p>
    
  • 组件类:

     import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
    
    	@Component({
    	  selector: 'app-layout',
    	  templateUrl: './layout.component.html',
    	})
    	export class LayoutComponent implements AfterViewInit{
    		//使用ViewChild获取,然后创建变量myP并且赋值,然后进行类型声明
    	  @ViewChild("myP") myP:ElementRef|undefined;
    	  ngAfterViewInit(): void {
    	    // 组件视图初始化完成之后的生命周期函数
    	    console.log(this.myP?.nativeElement)
    	  }
    	}
    
  1. 使用ViewChildren获取一组元素
  • 组件模版:
    <ul>
        <li #items>1</li>
        <li #items>2</li>
        <li #items>3</li>
        <li #items>4</li>
    </ul>
    
  • 组件类:
    import {AfterViewInit, Component, ElementRef, QueryList, ViewChildren} from '@angular/core';
    
    @Component({
      selector: 'app-layout',
      templateUrl: './layout.component.html',
    })
    export class LayoutComponent implements AfterViewInit{
      @ViewChildren('items') items: QueryList<HTMLLIElement> | undefined;
      ngAfterViewInit(): void {
        // 组件视图初始化完成之后的生命周期函数
        // QueryList对象有一个_result属性,里面存储的是element list,但是不能直接获取,只能使用toArray转换为数组
        console.log(this.items?.toArray());
      }
    }
    

(五)双向数据绑定

双向数据绑定应用于表单元素
Angular将双向数据绑定的功能放在了@angular/forms里面

  1. 需要在module中引入FormsModule
    在这里插入图片描述
  2. 在组件模版中的表单元素上使用[(ngModel)]
<input type="text" [(ngModel)]="value"/>
<h1>{{value}}</h1>
<button (click)="value='hello'">click</button>
  1. 在组件类中初始化value数据
export class LayoutComponent{
  public value: string = '';
}

(六)内容投影

类似于Vue中的组件插槽,子组件中的内容不是定义的时候就写好的,而是由父组件传递进去的。内容投影使用ng-content标签标识。ng-content起到占位的作用。分为两种情况:

  1. 父组件向子组件传递一块内容
  • 父组件模版:
    <app-bootstrap-panel>
        <div>向子组件传递过去的内容</div>
    </app-bootstrap-panel>
    
  • 子组件模版:
    <ng-content></ng-content>
    
  1. 父组件向子组件传递多块内容
  • 父组件模版:

    <app-bootstrap-panel>
        <div class="a">我是a</div>
        <div id="b">我是b</div>
    </app-bootstrap-panel>
    
  • 子组件模版:
    select使用css选择器选中父组件传递过来的元素,填充到对应位置

    <div style="color:red">
        <ng-content select=".a"></ng-content>
    </div>
    <div style="color:blue">
        <ng-content select="#b"></ng-content>
    </div>
    
  • 页面效果:
    在这里插入图片描述

    在填充的过程中,ng-content标签会被对应的父组件传递过来的标签所代替。
    在这里插入图片描述
    如果不想要这个额外的div,只想要里面的内容,可以使用ng-container标签
    父组件模版:

    <app-bootstrap-panel>
        <ng-container class="a">我是a</ng-container>
        <ng-container id="b">我是b</ng-container>
    </app-bootstrap-panel>
    

    HTML渲染出来的结构:
    在这里插入图片描述

(七)引入ng-bootstrap

  1. 下载ng-bootstrap
    ng add @ng-bootstrap/ng-bootstrap
    此命令顺便安装好了bootstrap依赖,如果没有需要手动安装
    在这里插入图片描述
    angular.json中也自动引入boostrap的样式文件
    在这里插入图片描述
  2. 在模块中引入ng-bootstrap
    • 在模块中
      在这里插入图片描述
    • 在该模块的组件中使用,就不需要在引入模块了,具体代码从官网拖拽即可。官网给出的例子使用的是独立组件即组件的属性standalone: true,后续再进行探究。
      ng-bootstrap在组件中使用

二、指令Directive

指令是Angular提供的用来操作DOM的途径,指令分为属性指令和结构指令

  • 属性指令:修改现有元素的外观或行为,给DOM元素设置属性,比如innerHTML,使用[]包裹,不会增加或删除DOM
  • 结构指令:通过逻辑判断来增加、删除DOM节点以修改布局,使用*作为指令前缀

(一)内置指令

  1. *ngIf

    <!--用法一:根据条件决定判断决定是否渲染当前DOM-->
    <div *ngIf="true">ngIf里面的条件判断为真</div>
    <!--用法二:根据条件判断决定渲染哪一个指定的DOM,为true时加载then指定的DOM,为false时加载else指定的DOM-->
    <!--必须使用ng-template标签才能识别-->
    <div *ngIf="true;then data else noData"></div>
    <ng-template #data>
        <p>ngIf里面的条件判断为真</p>
    </ng-template>
    <ng-template #noData>
        <p>ngIf里面的条件判断为假</p>
    </ng-template>
    

    条件判断为false时不会创建DOM元素
    在这里插入图片描述

  2. [hidden]
    根据条件判断决定是否隐藏元素,为true时隐藏,为false时不隐藏

    <div [hidden]="false">不隐藏</div>
    <div [hidden]="true">隐藏</div>
    

    控制display属性是否为none,隐藏时也会创建DOM元素
    在这里插入图片描述

  3. *ngFor

    • 基本用法
      index:获取索引
      even:当前元素索引是不是偶数
      odd:当前元素索引是不是奇数
      first:当前元素是不是第一个
      last:当前元素是不是最后一个
    	<ul>
    	<li
            *ngFor="
            let user of users;
            let i = index;
            let isEven = even;
            let isOdd = odd;
            let isFirst = first;
            let isLast = last"
    >
    ({{i}}) {{user.name}}
    </li>
    </ul>
    
    • 高级用法 *ngFor可以使用trackBy去追踪每一个元素,先说具体用法:
      组件模版中

      <ul>
      	    <li *ngFor="let user of users"> {{user.name}}
      	    </li>
      	</ul>
      	<!--使用trackBy-->
      	<div *ngFor="let item of users; trackBy: trackByItems">
              ({{item.id}}) {{item.name}}
          </div>
          <!--调用重新赋值的方法-->
          <button (click)="changeUser()">修改数组</button>
      

      组件类中:

      public users:User[] = [
      	    {id: 1, name: 'John'},
      	    {id: 2, name: 'Mary'},
      	    {id: 3, name: 'Steve'},
      	    {id: 4, name: 'Jane'},
        ]
        // 重新给users赋值
        changeUser(){
          this.users = [
            {id: 1, name: 'John'},
            {id: 2, name: 'Mary'},
            {id: 3, name: 'Steve'},
            {id: 4, name: 'Jane'},
            {id: 5, name: 'Tom'}
          ]
        }
        // 这个方法用来返回想要追踪的属性,可以是id,也可以是别的属性,最好是唯一标识
      trackByItems(index: number, user: User): number { return user.id; }
      

      在浏览器中运行,并且点击按钮,查看element的变化:
      在这里插入图片描述
      可以看到,不使用trackBy*ngFor数组的每一项对应的元素都被重新创建了,而使用trackBy*ngFor只有真正发生改变的那一项发生了重新渲染。默认Angualr会将数组作为一个整体,重复赋值时会整体销毁重建;而使用trackBy,Angular就可以可以追踪每一个元素,数组重新赋值时对比每一项的变化,只会重复创建有修改的项,起到节省性能的作用。

    (二)自定义指令

    1. 创建自定义指令
      使用Angular-cli提供的命令: ng g d directives/directiveDemo1
      在这里插入图片描述
      Angular会在相应的位置创建一个ts文件,并且在根模块中引入这个指令
      指令文件:

      import { Directive } from '@angular/core';
      @Directive({
        selector: '[appDirectiveDemo1]' // 通过属性的方式使用
      })
      export class DirectiveDemo1Directive {
        constructor() { }
      }
      

      根模块:
      在这里插入图片描述
      指令跟组件一样,必须属于某一个模块才能正常工作

    2. 使用自定义指令

    • 在根模块的模版文件中,在HTML元素上通过属性的方式使用自定义指令:
      <div appDirectiveDemo1>使用自定义指令</div>
      
    • 在指令内部获取当前DOM元素,有几点需要注意:
      1. 需要引入ElementRef服务,并且传递到constructor的形参中
      2. 在构造函数中根据参数进行数据初始化
      3. 操作DOM需要在AfterViewInit生命周期中,此时视图已经完成了初始化
      import {AfterViewInit, Directive, ElementRef } from '@angular/core';
      
      @Directive({
        selector: '[appDirectiveDemo1]' // 通过属性的方式使用
      })
      export class DirectiveDemo1Directive implements AfterViewInit {
        public element: HTMLElement;
        constructor(private elementRef: ElementRef) {
          this.element = elementRef.nativeElement;
        }
        ngAfterViewInit() {
          console.log(this.element);
          this.element.innerHTML = 'Hello World';
        }
      }	```
      
    • 查看页面效果:
      在这里插入图片描述
    1. 向自定义指令中传递数据
    • 模版组件中使用[]传递数据
      <div [appDirectiveDemo1]="{bgColor:'red'}">使用自定义指令</div>
      
    • 指令中通过@Input装饰器,获取传递进来的数据,并且创建变量进行赋值,并且需要指定一个初始化的值
      // 定义Options接口,用于接收传入的参数
      interface Options {
        bgColor?: string;
      }
      // ...
      export class DirectiveDemo1Directive implements AfterViewInit {
        @Input("appDirectiveDemo1") styleOptions: Options = {};
        // ...
      }
      
    1. 给DOM元素绑定事件:鼠标移入字体变黄,鼠标移出变成默认颜色,如果没有指定默认颜色就变为skyblue色
      给元素绑定事件需要使用@HostListener装饰器
      	// onMouseEnter:自定义的函数名
          @HostListener('mouseenter') onMouseEnter() {
              this.element.style.color = 'yellow';
          }
          // onMouseLeave:自定义的函数名
          @HostListener('mouseleave') onMouseLeave() {
              this.element.style.color = this.styleOptions.bgColor || 'skyblue';
          }
      
    	
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值