MST

星途 面试题库

面试题:Angular插值表达式与模板在复杂业务场景下的深度应用

假设你正在开发一个电商平台的商品展示模块,需要展示商品的各种信息,包括价格、库存、促销信息等,并且这些信息需要实时动态更新。同时,用户可以对商品进行筛选和排序操作。请详细描述如何使用Angular插值表达式与模板结合来实现该复杂业务场景,包括数据绑定方式、变化检测机制以及如何处理数据的实时更新,给出完整的代码架构和关键代码片段。
41.0万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

1. 数据绑定方式

在Angular中,对于商品信息展示,主要使用以下几种数据绑定方式:

  • 插值表达式:用于在模板中显示数据,例如 {{product.price}}
  • 属性绑定:当需要动态设置HTML元素属性时使用,比如根据库存显示不同的样式:<div [class.out - of - stock]="product.stock === 0">...</div>
  • 事件绑定:用于处理用户操作,如筛选和排序按钮的点击事件,<button (click)="sortProducts('price')">按价格排序</button>

2. 变化检测机制

Angular默认使用Zone.js来检测变化。Zone.js会拦截异步操作(如HTTP请求、定时器等),当这些异步操作完成时,Angular会检查组件树中所有组件的数据变化,并更新视图。对于复杂场景,若需要手动触发变化检测,可以注入 ChangeDetectorRef 并调用 detectChanges() 方法。

3. 处理数据的实时更新

  • HTTP轮询:可以定期通过HTTP请求获取最新数据,在服务中使用 intervalswitchMap 实现轮询:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class ProductService {
  constructor(private http: HttpClient) {}

  getProducts() {
    return interval(5000).pipe( // 每5秒请求一次
      switchMap(() => this.http.get('/api/products'))
    );
  }
}
  • WebSocket:更适合实时更新场景,使用 @stomp/stompjs 库:
import { Injectable } from '@angular/core';
import * as Stomp from '@stomp/stompjs';
import * as SockJS from'sockjs - client';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class WebSocketService {
  private stompClient: any;
  constructor() {}

  connect() {
    const socket = new SockJS('/websocket - endpoint');
    this.stompClient = Stomp.over(socket);
    const that = this;
    return new Observable((observer) => {
      this.stompClient.connect({}, function(frame) {
        that.stompClient.subscribe('/topic/products', function(product) {
          observer.next(JSON.parse(product.body));
        });
      }, function(error) {
        observer.error(error);
      });
    });
  }
}

4. 完整代码架构

  • 组件结构
src/
├── app/
│   ├── product - list/
│   │   ├── product - list.component.ts
│   │   ├── product - list.component.html
│   │   ├── product - list.component.css
│   │   └── product - list.component.spec.ts
│   ├── product - service.ts
│   ├── app.component.ts
│   ├── app.component.html
│   ├── app.component.css
│   └── app.module.ts
  • 关键代码片段
    • product - list.component.ts
import { Component, OnInit } from '@angular/core';
import { ProductService } from '../product - service';
import { WebSocketService } from '../web - socket.service';

@Component({
  selector: 'app - product - list',
  templateUrl: './product - list.component.html',
  styleUrls: ['./product - list.component.css']
})
export class ProductListComponent implements OnInit {
  products: any[] = [];
  constructor(private productService: ProductService, private webSocketService: WebSocketService) {}

  ngOnInit() {
    // 使用HTTP轮询获取数据
    this.productService.getProducts().subscribe((products) => {
      this.products = products;
    });

    // 使用WebSocket实时更新数据
    this.webSocketService.connect().subscribe((product) => {
      const index = this.products.findIndex(p => p.id === product.id);
      if (index!== -1) {
        this.products[index] = product;
      } else {
        this.products.push(product);
      }
    });
  }

  sortProducts(field: string) {
    this.products.sort((a, b) => {
      if (field === 'price') {
        return a.price - b.price;
      }
      // 其他排序逻辑
      return 0;
    });
  }

  filterProducts(filter: string) {
    // 实现筛选逻辑
    this.products = this.products.filter(product => {
      // 根据筛选条件过滤
      return true;
    });
  }
}
  • product - list.component.html
<div class="product - list">
  <input type="text" [(ngModel)]="filterText" placeholder="筛选商品">
  <button (click)="filterProducts(filterText)">筛选</button>
  <button (click)="sortProducts('price')">按价格排序</button>

  <div *ngFor="let product of products" class="product">
    <h3>{{product.name}}</h3>
    <p>价格: {{product.price}}</p>
    <p>库存: {{product.stock}}</p>
    <p *ngIf="product.promotion">{{product.promotion}}</p>
    <div [class.out - of - stock]="product.stock === 0">商品缺货</div>
  </div>
</div>
  • app.module.ts
import { BrowserModule } from '@angular/platform - browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { ProductListComponent } from './product - list/product - list.component';
import { ProductService } from './product - service';
import { WebSocketService } from './web - socket.service';

@NgModule({
  declarations: [
    AppComponent,
    ProductListComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [ProductService, WebSocketService],
  bootstrap: [AppComponent]
})
export class AppModule {}