ng11 开发记录

1.nzViewContainerRef 什么作用?

// 导入 NzModalService 模块
import { NzModalService } from 'ng-zorro-antd/modal';

// 在组件中注入 NzModalService 服务
constructor(private modal: NzModalService) {}
setTempValue() {
// 调用 create 方法创建模态框
const NzModalRef =this.modal.create({
  nzTitle: '室温未达标用户', // 模态框的标题
  nzWidth: '80vw', // 模态框的宽度
  nzStyle: { top: '60px', bottom: '10px' }, // 模态框的样式
  nzContent: MonitorRoomtAbnormalUsersModalComponent, // 模态框的内容,可以是一个组件或者一个模板
  nzViewContainerRef: this.viewContainerRef, // 指定模态框的视图容器,用于嵌入组件或者模板
  nzFooter: null, // 模态框的底部,可以是一个按钮数组或者一个模板,设置为 null 表示不显示底部
  nzMaskClosable: false, // 是否允许点击遮罩层关闭模态框,默认为 true
  nzClosable: true, // 是否显示右上角的关闭按钮,默认为 true
 // 传递给模态框内容组件的参数,可以在组件中通过 @Input() 接收
  nzComponentParams: {
  aligntime:this.aligntime,
    tab_showType:this.tab_showType,
    menuId:this.menuId,
    minT:this._minT,
    maxT:this._maxT,
    baseInfo:{
    field:this._overviewData.field,
    id:this._overviewData.id,
    type:"wdb"
        }
    }
});
 
  // 订阅NzModalRef 实例上的 setTempValue 事件
  NzModalRef.componentInstance.setTempValue.subscribe((res: any) => {
      console.log('子组件触发了自定义事件:', res);
      // 在这里执行相应的操作
      if (res === 'reset') {
        this.maxValue =this.dataMax= this.maxValueCopy;
        this.minValue =this.dataMin= this.minValueCopy;
     
    // 通过下面的方式修改,NzModalRef 实例的 componentInstance 属性中的 maxValue 属性值设置为 this.maxValueCopy 的值。子组件的值就会更新
        NzModalRef.componentInstance.maxValue=this.maxValueCopy
        NzModalRef.componentInstance.minValue=this.minValueCopy

      } else {
        this.dataMin = res.maxValue;
        this.dataMax = res.minValue;
      }
     
      this.getChartData(this.detailData);
    });
 }
 
 
子组件:
export class MonitorRoomtUserDetailSettempvalueModalComponent implements OnInit {
  @Input() maxValue: number;
  @Input() minValue: number;
  @Output() readonly setTempValue = new EventEmitter();

  constructor() {}

  ngOnInit(): void {}


  resetValue() {
    this.setTempValue.emit('reset');
  }
  valueBlur() {
    console.log(this.maxValue);
    console.log(this.minValue);
    let obj = { maxValue: this.maxValue, minValue: this.minValue };
    this.setTempValue.emit(obj);
  }
}

nzViewContainerRef 是 ng-zorro-antd 库中 ModalService 的一个选项参数,用于指定模态框内容要插入的视图容器。它的作用是将模态框的内容组件插入到指定的视图容器中,以便在模态框中显示该组件的内容。

通常情况下,nzViewContainerRef 会被设置为组件类中的 ViewContainerRef 对象,以确保模态框的内容组件被正确地插入到组件的视图容器中。这个参数是可选的,如果不指定,则默认为 body,即将模态框的内容插入到页面的 body 元素中。

 

 

 

2.求数组中 t_data 转为number类型时的最大值

const arr = [
{maxT:1,minT:2,t_data:""},
{maxT:1,minT:2,t_data:" "},
{maxT:1,minT:2,t_data:"123"},
{maxT:1,minT:2,t_data:"13"},
{maxT:1,minT:2,t_data:undefined},
{maxT:1,minT:2,t_data:null},
{maxT:1,minT:2,t_data:222},
{maxT:1,minT:2,t_data:0},
];

const maxTData = arr.reduce((max, obj) => {
const curr = Number(obj.t_data);
if (!isNaN(curr)) {
// 如果t_data可以转换为数字,进行比较
max = Math.max(max, curr);
}
return max;
}, -Infinity);

console.log(maxTData); // 输出 222

 3.修改nz-modal弹窗样式

 ::ng-deep .nzDataDetailClass{
    .ant-modal-title{
        font-weight: 700 !important;
    }

    font-size: 25px !important;
     .tools{
         display: flex;
         align-items: center;
        font-weight: bold;
         div{
             margin-right: 20px;
         }
     }
   }
 
 
4.angular响应式表单模板驱动表单
好的,我会给出两个更详细的 Angular 表单示例,一个是响应式表单的示例,另一个是模板驱动表单的示例。

1. Angular 响应式表单示例

```typescript
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-reactive-form',
  template: `
    <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
      <label>
        Name:
        <input type="text" formControlName="name">
        <div *ngIf="profileForm.controls.name.invalid && profileForm.controls.name.touched">
          Name is required.
        </div>
      </label>

      <label>
        Email:
        <input type="email" formControlName="email">
        <div *ngIf="profileForm.controls.email.invalid && profileForm.controls.email.touched">
          Enter a valid email.
        </div>
      </label>

      <button type="submit" [disabled]="!profileForm.valid">Submit</button>
    </form>
  `
})
export class ReactiveFormComponent implements OnInit {

  profileForm: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.profileForm = this.fb.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]],
    });
  }

  onSubmit() {
    // Handle submit logic.
    console.log(this.profileForm.value);
  }

}
```

上述示例中,我们使用模板中的 `formGroup` 指令绑定表单控制器,使用 `formControlName` 绑定每个表单控件到相应的表单控制器中。
我们还为每个控件添加了一些基本验证(例如必填和电子邮件格式),并利用 `
*ngIf` 指令来显示错误信息。 2. Angular 模板驱动表单示例 ```html <form #profileForm="ngForm" (ngSubmit)="onSubmit(profileForm.value)"> <label> Name: <input type="text" name="name" [(ngModel)]="name" required> <div *ngIf="profileForm.controls['name'].invalid && (profileForm.controls['name'].dirty || profileForm.submitted)"> Name is required. </div> </label> <label> Email: <input type="email" name="email" [(ngModel)]="email" required email> <div *ngIf="profileForm.controls['email'].invalid && (profileForm.controls['email'].dirty || profileForm.submitted)"> Enter a valid email. </div> </label> <button type="submit" [disabled]="!profileForm.valid">Submit</button> </form> ``` 上述示例中,我们使用 `ngForm` 指令绑定表单控制器使用 `ngModel` 绑定每个表单控件到组件的相应属性中。我们还为每个控件添加了一些基本验证(例如必填和电子邮件格式),
并利用 `
*ngIf` 指令来显示错误信息。 我们在模板中也添加了一些逻辑,例如利用 `#profileForm` 变量来引用 `ngForm` 指令创建的表单控制器,以及在表单提交时调用自定义 `onSubmit()` 方法。

 

5.ng-alain登录验证 代码逻辑分析:
this.userName.markAsDirty()和this.userName.updateValueAndValidity() 如果不使用会有什么影响?
如果没有调用 `markAsDirty()` 方法,表单控件将保持其原始状态(通常是 "pristine")不变,即使在用户输入了值以后,控件的状态依然不是 "dirty",因此不会触发验证器的执行操作。
这意味着,如果没有调用 `markAsDirty()` 方法,即使用户输入了一个无效值,也不会检查表单控件的有效性,并且表单控件状态也不会相应更新,因此使用该值进行表单提交可能会导致预期之外的结果。 同样,如果没有调用 `updateValueAndValidity()` 方法,表单控件将保持其原始状态,不会执行验证器的操作,这意味着即使用户输入了一个无效值,表单控件的状态也不会相应更新,因此使用该值进行表单提交也可能会导致预期之外的结果。 因此,确保在表单提交之前调用这两个方法是非常重要的,以确保表单控件状态得到更新,并执行验证器的操作,以便在提交之前验证用户输入的值是否有效。
 
6.`ChangeDetectionStrategy.OnPush`
ChangeDetectionStrategy.OnPush是 Angular 中的一种更优化的变更检测策略,它可显著提升应用程序的性能。
使用 `ChangeDetectionStrategy.OnPush` 策略需要注意以下几点:
1- 在 Angular 组件实现中,在 `@Component` 装饰器下添加 `changeDetection: ChangeDetectionStrategy.OnPush` 属性。
2. - 在 `ChangeDetectionStrategy.OnPush` 策略下,Angular 只会检测有输入属性变化的组件,即只有当组件的输入属性发生变化时,Angular 才会执行组件的变更检测。因此,应该避免频繁地更改组件的输入属性,以减少检测的次数。
3- 在 `ChangeDetectionStrategy.OnPush` 策略下,当使用 `Observable` 或 `Promise` 等异步数据源进行数据绑定时,必须手动触发变更检测流程。可以通过 RxJS 的 `ChangeDetectorRef` 注入器服务的 `detectChanges()` 方法来实现
4- 在使用 `ChangeDetectionStrategy.OnPush` 策略时,应避免在组件中频繁更改引用类型的属性,因为这不会触发组件的变更检测。相反,可以通过创建新的引用来更改属性,以触发组件的变更检测
案例一 单独组件 手动触发 无接口请求时 :
import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'app-example',
  template: `
    <h2>{{title}}</h2>
    <p>{{text}}</p>
    <button (click)="updateTitle()">Update Title</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush // 将变化检测策略设置为OnPush
})
export class ExampleComponent {
  @Input() title: string;
  @Input() text: string;

  constructor(private cdr: ChangeDetectorRef) {} // 注入 ChangeDetectorRef

  updateTitle() {
    this.title = 'New Title';
    this.cdr.detectChanges(); // 手动触发变化检测
  }
}

案例二 单独组件 手动触发  接口请求时:

import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { UserService } from '../user.service';

@Component({
  selector: 'app-list',
  template: `
    <div *ngFor="let user of users">{{ user.name }} - {{ user.email }}</div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListComponent {
  users: any[] = [];

  constructor(private userService: UserService, private cd: ChangeDetectorRef) {}

  ngOnInit(): void {
    this.userService.getUsers().subscribe(users => {
      this.users = users;
      // 手动触发变更检测
      this.cd.detectChanges();
    });
  }
}

 

 
案例三 在父子组件传值场景下,可以使用ChangeDetectionStrategy.OnPush策略来避免不必要的视图更新。
父子传值 通过创建新的引用(...解构赋值)来更改属性,触发组件的变更监测:
### 注意事项

1. 当使用 `OnPush` 策略时,你应该避免在组件内部直接修改输入属性,而是通过父组件进行修改。这是因为 `OnPush` 只在输入属性发生变化时才会触发变更检测。

2. 如果你需要在组件内部更新视图,请使用 `ChangeDetectorRef` 的 `markForCheck()` 方法或者使用detectChanges()。这将告诉 Angular 下一次变更检测周期应该检查该组件及其子组件。

3. 在使用 `OnPush` 策略的组件中,`ngDoCheck()` 和 `ngAfterViewChecked()` 生命周期钩子将更少地被触发,因为变更检测的频率减少了。

### 代码示例

以下示例展示了如何使用 `OnPush` 策略:

**parent.component.html**

```html
<app-child [data]="data" (update)="onUpdate($event)"></app-child>
<button (click)="changeData()">Change Data</button>
```

**parent.component.ts**

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {
  data = {
    value: 'Initial data'
  };

  changeData() {
    this.data = { ...this.data, value: 'Updated data' };
  }

  onUpdate(newData) {
    this.data = newData;
  }
}
```

**child.component.html**

```html
<p>{{ data.value }}</p>
<button (click)="updateData()">Update Data</button>
```

**child.component.ts**

```typescript
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
  @Input() data;
  @Output() update = new EventEmitter();

  updateData() {
    const newData = { ...this.data, value: 'Updated data from child' };
    this.update.emit(newData);
  }
}
```

在这个示例中,`ChildComponent` 使用了 `OnPush` 策略。当父组件中的按钮被点击时,输入属性 `data` 的值会发生变化,从而触发子组件的变更检测。
子组件内部的更新操作通过 `EventEmitter` 传递给父组件,父组件负责实际更新数据。这样保持了 OnPush 策略的性能优化。

7.Subscription

Subscription是RxJS中的一种对象类型,用于管理Observable流数据的订阅和取消订阅

在Angular应用中,我们通常使用Subscription来订阅组件或服务中的Observable对象。通常情况下,我们应该将Subscription对象保存在组件或服务的属性中,以便在组件或服务销毁时及时取消订阅,避免内存泄漏。 可以通过调用Subscription对象的unsubscribe()方法来取消订阅,也可以使用RxJS提供的诸如takeUntil等操作符来自动取消订阅。

以下是一个Angular组件中订阅Observable并管理Subscription的示例代码:
```typescript
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable, Subscription } from 'rxjs';

import { DataService } from './data.service';

@Component({
  selector: 'app-example',
  template: `
    <h1>{{ data }}</h1>
  `,
})
export class ExampleComponent implements OnInit, OnDestroy {
  data: string;
  data$: Observable<string>;
  subscription: Subscription;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.data$ = this.dataService.getData();
    this.subscription = this.data$.subscribe(
      (data) => {
        this.data = data;
      },
      (error) => {
        console.error(error);
      }
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
```

在上面的代码中,我们首先在组件中声明了一个名为data的属性和data$的Observable属性以用于在模板中显示数据。

在ngOnInit生命周期钩子中,我们通过调用getData()方法订阅了一个数据流,并将数据流中的数据保存在组件中声明的data属性中。

在ngOnDestroy生命周期钩子中,我们在组件销毁时通过调用subscription对象的unsubscribe()方法来取消订阅该数据流,以便避免内存泄漏。

 

8.
import { Platform } from '@angular/cdk/platform';
Platform:平台

this.platform.isBrowser是指当前应用是否在浏览器中运行,它是Angular中一个与平台相关的服务PlatformLocation中的属性。

在Angular应用中,由于我们通常会将应用部署在不同的平台和环境中,因此我们需要知道应用当前是在哪个平台上运行。Angular提供了PlatformLocation服务来获取该信息。

在浏览器中运行的Angular应用使用BrowserPlatformLcoation对象,而在Web Worker中运行的应用使用WebWorkerPlatformLocation对象。这两个对象都继承了PlatformLocation基类,因此都具有isBrowser属性。

isBrowser属性是一个布尔类型的值,用于判断当前应用是否在浏览器中运行。如果值为true,表示应用在浏览器中运行;如果值为false,则表示应用不在浏览器中运行。在当前代码中,如果判断isBrowser为false,则直接返回,不再执行后面的逻辑。

 
 
 9.`let-i` 是 Ng Alain 库中 ST 表格组件的语法糖,也称之为模板变量。
它允许开发者在表格行数据中使用自定义变量,便于在模板中直接使用数据。在这里,`let-i` 的作用是将“当前行的数据”赋值给 `i` 变量,以便在该行数据中的其他列(如第一列)中使用 `i` 变量。 和 Vue 中的 `slot-scope` 用法类似,但是不完全相同。使用 `let-i` 可以在当前行上下文中引入该行的数据,而 `slot-scope` 可以使父组件向子组件传递具有相同属性的上下文并进行局部调整。 需要注意的是,虽然用法类似,但是 `let-i` 只能在 ST 表格组件内使用。如果你要使用该功能,请确保依赖的 Ng Alain 库已经正确安装,并参考 API 中的相关文档进行使用。
 
10.render2
Angular 使用 `Renderer2` 是为了提供一种抽象层,使您可以在不同的平台(如浏览器、服务器端渲染、Web Workers 和原生移动应用)之间跨平台地操作DOM元素。
`Renderer2` 解决了直接使用 `ElementRef` 和原生 DOM API 时可能出现的跨平台兼容性问题。 使用 `Renderer2` 可以保持您的组件代码更加干净、可维护,同时避免与特定平台相关的问题。 下面是一个使用 `Renderer2` 的简单示例: ```typescript import { Component, ElementRef, Renderer2 }
from '@angular/core'; @Component({ selector: 'app-example', template: ` <button (click)="changeBackgroundColor('red')">Change background color to red</button> <div #content>Some content here...</div> `, }) export class ExampleComponent { constructor(private el: ElementRef, private renderer: Renderer2) {} changeBackgroundColor(color: string): void { const contentDiv = this.el.nativeElement.querySelector('div'); this.renderer.setStyle(contentDiv, 'background-color', color); } } ``` 在这个示例中,我们创建了一个组件,其中有一个按钮和一个包含文本内容的 `div`。当用户点击按钮时,`div` 的背景颜色会发生变化。
我们使用 `Renderer2` 的 `setStyle` 方法来实现这个功能,而不是直接操作 DOM 元素。这样,无论我们在哪个平台上使用这个组件,它都能正常工作。

 11.

import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild }  from  '@angular/core' ; 
import { Subject } from 'rxjs' ;
import { takeUntil } from 'rxjs/operators' ;
import { NzTableComponent } from 'ng-zorro-antd/table' ;

private destroy$ = new Subject();
this .nzTableComponent?.cdkVirtualScrollViewport?.scrolledIndexChange .pipe(takeUntil( this .destroy$)) .subscribe((data: number) => { console.log( 'scroll index to' , data); }); 这段代码监听了 `(cdkVirtualScrollViewport)` 对象的 `scrolledIndexChange` 事件,当用户滚动列表,且当前选择的行发生变化时,触发一个回调函数,该回调函数将参数 `data` 设置为当前被选择的行的索引值,
然后在控制台中输出一条日志信息。

`takeUntil( this .destroy$)` 用来确保在组件被销毁前取消订阅,以避免内存泄漏。此判断表达式中的 `?.` 表示如果该变量存在,才会访问该变量的属性或方法,否则跳过该语句不执行。

  

接上 
ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } 这段代码是一个 Angular 组件的生命周期钩子函数 `ngOnDestroy()`。它在组件被销毁时被调用,用于清理组件中的变量、取消未完成的 HTTP 请求或 RxJS 订阅等。
在这个例子中,它通过调用 `next()` 方法通知订阅它的可观察对象停止发送事件并通过调用 `complete()` 方法标记这个可观察对象的结束。这样做可以确保在组件销毁时,
所有的订阅和异步操作都被正确地清理,以避免内存泄漏等问题。

12.angular TemplateRef<{ $implicit: T, index: number }> 作用和使用

`TemplateRef<{ $implicit: T, index: number }> ` 是 Angular 中的一种模板引用类型,用于在组件中将一个模板作为参数传递到另一个组件或指令中,并在那里进行使用。

其中,`T` 是模板中的数据类型,`$implicit` 和 `index` 是对象属性名称,分别表示数据索引。在模板中,可以通过前缀 `let-` 来访问 `$implicit` 和 `index` 属性,并将它们绑定到当前模板的变量中。

使用 `TemplateRef<{ $implicit: T, index: number }>` 时,我们可以通过以下步骤进行定义和使用:

1. 在模板中,定义一个模板引用变量,并将其类型设置为 `TemplateRef<{ $implicit: T, index: number }> `。例如:

   ```html
   <ng-template #myTemplate let-data>
     <div>{{data.index}} : {{data.name}}</div>
   </ng-template>
   ```

在上面的例子中,我们定义了一个模板引用变量 `myTemplate`,并将其类型设置为 `TemplateRef<{ $implicit: T, index: number }> `。
模板中的 `let-data` 表示将模板输入变量 `$implicit` 绑定到名为 `data` 的变量上,其中 `$implicit` 表示模板中的数据`index` 表示当前渲染的对象在数据数组中的索引值2. 在需要使用该模板的组件或指令中,使用 `@ViewChild` 装饰器获取到该模板引用变量,并将其类型设置为 `TemplateRef<{ $implicit: T, index: number }> `。
例如: ```typescript @ViewChild(
'myTemplate', { static: true }) myTemplate!: TemplateRef<{ $implicit: VirtualDataInterface, index: number }>; ``` 在上面的例子中,我们通过 `@ViewChild` 装饰器获取了名为 `myTemplate` 的模板引用变量,并将其类型设置为 `TemplateRef<{ $implicit: VirtualDataInterface, index: number }> `,
其中 `VirtualDataInterface` 表示模板中绑定的数据类型。
3. 在使用该模板的组件中,使用 `ngTemplateOutlet` 指令将该模板注入到指定的 HTML 元素中。例如: ```html <div *ngFor="let data of datas; let i=index" [ngTemplateOutlet]="myTemplate" [ngTemplateOutletContext]="{ $implicit: data, index: i }"></div> ``` 在上面的例子中,我们使用 `*ngFor` 指令遍历组件中的 `datas` 数组,将每个数组元素渲染成一个 HTML 元素,然后使用 `ngTemplateOutlet` 指令将模板注入到该 HTML 元素中
并使用 `ngTemplateOutletContext` 属性将数据和索引传递到模板中。这样,模板就可以使用 `data` 绑定模板输入变量 `$implicit`,使用 `i` 绑定模板输入变量 `index`,并展示出渲染后的结果。

使用案例:

在 `nz-table` 中,可以使用 `ng-template` 来自定义每行的渲染方式。在这个 `ng-template` 中,可以使用 `TemplateRef<{ $implicit: T, index: number }>` 模板引用变量来传递当前行数据和索引。

例如:

```html
<nz-table #myTable [nzData]="data">
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
    </tr>
  </thead>
  <tbody>
    <ng-container *ngFor="let item of myTable.data; let i=index">
      <tr>
        <td>
          <ng-container *ngTemplateOutlet="nameTemplate; context: { $implicit: item, index: i }"></ng-container>
        </td>
        <td>{{ item.age }}</td>
      </tr>
    </ng-container>
  </tbody>
</nz-table>

<!-- 定义一个名字的模板 -->
<ng-template #nameTemplate let-data let-i="index">
  {{ i + 1 }} - {{ data.name }}
</ng-template>
```

在上面的代码中,我们使用了 `ng-container` 来遍历 `nz-table` 的数据,并使用 `TemplateRef<{ $implicit: T, index: number }>` 模板引用变量来传递当前行的数据和索引到 `nameTemplate` 模板中。
这样,在 `nameTemplate` 模板中,我们就可以使用 `data` 和 `i` 来访问当前行的数据和索引了。

 13.viewProviders

在Angular中,`@Component`装饰器用于定义组件。其中,`viewProviders`是一个可选的属性,用于在组件的模板中注册需要的依赖。

具体来说,如果我们需要在组件的模板中使用某个服务,就可以将该服务的提供者添加到`viewProviders`中。这样,该服务就会被注入到组件的视图(即模板)中,并可以在模板中使用。

下面是一个示例,展示了如何在`viewProviders`中注册一个服务:

```typescript
import { Component } from '@angular/core';
import { Greeter } from './greeter.service';

@Component({
  selector: 'app-greeting',
  template: '<h1>{{ greeting }}</h1>',
  viewProviders: [Greeter],
})
export class GreetingComponent {
  constructor(private greeter: Greeter) {}

  get greeting(): string {
    return this.greeter.greet('world');
  }
}
```

在这个示例中,我们定义了一个组件`GreetingComponent`,并指定了它的选择器(`selector`)、模板(`template`)以及`viewProviders`属性,将`Greeter`服务的提供者添加到组件的模板中。

在组件的构造函数中,我们通过将`Greeter`标记为私有成员变量,将该服务注入到组件中,并在`get greeting()`方法中使用它来生成欢迎语句。

最终,当我们在应用中使用`<app-greeting></app-greeting>`标签时,该组件会渲染出一个包含欢迎语句的`<h1>`元素。

总之,`viewProviders`通常情况下,如果一个服务只需要在一个组件的视图中使用,而不需要在整个组件及其子组件中使用,那么我们就可以将该服务的提供者添加到组件的viewProviders属性中。这样可以使该服务只在该组件及其视图中可用,而不会影响到其他组件。

 

14.

1. *ngIfng-template是用于条件渲染的结构指令结构指令的模板

2. 结构指令*ngTemplateOutletng-template来实现模板重用和条件渲染

`*ngIf`和`ng-template`通常与`div`标签一起使用,以实现条件渲染的目的。具体来说,在模板中可以使用以下语法:

```html
<div *ngIf="condition; else elseBlock">...</div>
<ng-template #elseBlock>...</ng-template>
```

在这段代码中,当`condition`为`true`时,`div`标签和其中的内容就会被渲染出来。否则,模板则会根据`#elseBlock`来进行渲染。

类似地,`ng-container`和`*ngTemplateOutlet`和`ng-template`可以一起使用,以实现模板的重用。具体来说,在模板中可以使用以下语法:

```html
<ng-container *ngTemplateOutlet="templateRef"></ng-container>
<ng-template #templateRef>...</ng-template>
```
或者

<ng-container *ngIf="isLoading; else loaded">
  <ng-container *ngTemplateOutlet="loading"></ng-container>
</ng-container>

<ng-template #loading>
  <div class="loading-spinner">Loading...</div>
</ng-template>

<ng-template #loaded>
<!-- loaded显示内容 -->
</ng-template> 在这段代码中,`ng
-container`不会影响样式和布局,充当一个临时容器的角色,它会从`ng-template`中引用内容,并将其插入到DOM中。`ng-template`则定义了一个可复用的模板内容,当需要显示这个模板时,
可以通过`*ngTemplateOutlet`指令来引用它并将其渲染到`ng-container`中。 总之,`*ngIf`和`ng-template`结合`div`等常用标签使用,用于条件渲染;`ng-container`和`*ngTemplateOutlet`和`ng-template`结合使用,用于模板的重用。

 

 

 

 

 

 

 

 

 

 

 
posted @ 2023-03-30 14:53  赵辉Coder  阅读(264)  评论(0编辑  收藏  举报