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
相关产品推荐
相关产品推荐

