You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular应用中局部实现View Transitions API的方案咨询

实现局部区域的View Transition动画

1. 关闭全局自动触发的整屏过渡

先修改全局配置,禁用路由自动触发的整屏View Transition,避免默认的全页面动画:

// app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, withViewTransitions({
      skipInitialTransition: true,
      // 禁用自动路由过渡,改为手动触发
      onViewTransitionCreated: () => false
    })),
    // ...其他提供者
  ]
};

2. 在ProductGrid组件中手动触发局部过渡

在product-grid.component.ts里监听分类选择变化,当分类切换时,调用document.startViewTransition()包裹视图更新逻辑:

import { Component, OnInit, inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ProductSelectors } from '../state/product/product.selectors';
import { CategorySelectors } from '../state/category/category.selectors';
import { Product } from '../models/product.model';
import { ProductActions } from '../state/product/product.actions';

@Component({
  selector: 'app-product-grid',
  templateUrl: './product-grid.component.html',
  styleUrls: ['./product-grid.component.scss']
})
export class ProductGridComponent implements OnInit {
  filteredProducts$!: Observable<Product[]>;
  private store = inject(Store);
  private currentCategoryId: string | null = null;

  ngOnInit() {
    // 监听分类变化,触发局部过渡
    this.store.select(CategorySelectors.selectSelectedCategoryId).subscribe(newCategoryId => {
      if (newCategoryId !== this.currentCategoryId) {
        this.currentCategoryId = newCategoryId;
        // 启动View Transition,状态更新由NgRx自动处理
        document.startViewTransition(() => {});
      }
    });

    this.filteredProducts$ = combineLatest([
      this.store.select(ProductSelectors.selectAllProducts),
      this.store.select(CategorySelectors.selectSelectedCategoryId),
    ]).pipe(
      map(([products, selectedCategoryId]) => {
        return selectedCategoryId 
          ? products.filter(p => p.categoryId === selectedCategoryId) 
          : products;
      })
    );

    // 加载商品逻辑保留
    this.store.select(ProductSelectors.selectAllProducts).subscribe(products => {
      if (!products?.length) {
        this.store.dispatch(ProductActions.loadProducts());
      }
    });
  }
}

3. 给商品列表容器添加过渡标识

在product-grid.component.html中,给包裹商品列表的容器添加view-transition-name属性,指定唯一标识让浏览器识别过渡区域:

<!-- 商品列表容器 -->
<div class="product-grid-container" style="view-transition-name: product-grid;">
  <mat-grid-list cols="3" rowHeight="2:3">
    <mat-grid-tile *ngFor="let product of filteredProducts$ | async" [colspan]="1">
      <div class="product-card">
        <img [src]="product.image" alt="{{product.name}}">
        <h3>{{product.name}}</h3>
        <p>{{product.price | currency}}</p>
      </div>
    </mat-grid-tile>
  </mat-grid-list>
</div>

4. 定义CSS过渡效果

在product-grid.component.scss中添加自定义过渡动画样式:

/* 商品网格的过渡动画 */
::view-transition-old(product-grid) {
  animation: fade-out 0.3s ease-in-out forwards;
}

::view-transition-new(product-grid) {
  animation: fade-in 0.3s ease-in-out forwards;
}

@keyframes fade-out {
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0; transform: scale(0.95); }
}

@keyframes fade-in {
  from { opacity: 0; transform: scale(1.05); }
  to { opacity: 1; transform: scale(1); }
}

/* 隐藏全局根元素的过渡,确保只有局部区域生效 */
::view-transition-group(root),
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  opacity: 0;
}

核心逻辑说明

  • document.startViewTransition()会在调用时捕获当前DOM快照,等待NgRx状态更新完成后再捕获新快照,自动生成过渡动画。
  • view-transition-name必须是页面唯一值,确保浏览器只针对该区域执行过渡。
  • 全局根元素的过渡被强制隐藏,避免整屏动画干扰局部效果。

内容的提问来源于stack exchange,提问作者infodev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:34:52