Angular组件多模板下的局部手风琴式动画实现咨询
Hey there! Let's tackle this accordion animation for your production-grade card layout. Since you're working with Angular (given the ng-content reference), here's a maintainable, component-friendly approach that fits your existing structure:
Core Approach
We'll leverage Angular's built-in Animation module to add state-driven transitions to your Card component. The goal is to animate the internal content area (the part with ng-content) when toggling, while keeping the header and summary bottom fixed (or optionally animating them too, if needed).
Step 1: Set Up Animation Dependencies
First, make sure the Angular Animations module is imported in your root module:
// app.module.ts import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ BrowserAnimationsModule, // ... other imports ] }) export class AppModule { }
Step 2: Update the Base Card Component
Modify your base Card component to include a toggle state, animation triggers, and click handling for the header.
Card Component Class (card.component.ts)
import { Component, Input } from '@angular/core'; import { trigger, state, style, animate, transition } from '@angular/animations'; @Component({ selector: 'app-card', templateUrl: './card.component.html', styleUrls: ['./card.component.css'], animations: [ trigger('accordionAnimation', [ state('expanded', style({ height: '*', opacity: 1, overflow: 'visible' })), state('collapsed', style({ height: '0', opacity: 0, overflow: 'hidden' })), transition('expanded <=> collapsed', animate('300ms ease-in-out')) ]) ] }) export class CardComponent { @Input() isExpanded = true; // Default to expanded @Input() headerTitle: string; @Input() summaryText: string; toggleExpansion(): void { this.isExpanded = !this.isExpanded; } }
Card Template (card.component.html)
<div class="card-container"> <!-- Card Header (toggle trigger) --> <div class="card-header" (click)="toggleExpansion()" role="button" [attr.aria-expanded]="isExpanded"> <h3>{{ headerTitle }}</h3> <span class="toggle-icon">{{ isExpanded ? '▼' : '▶' }}</span> </div> <!-- Animated Internal Content --> <div class="card-content" [@accordionAnimation]="isExpanded ? 'expanded' : 'collapsed'"> <ng-content></ng-content> </div> <!-- Card Summary Bottom --> <div class="card-footer"> <p>{{ summaryText }}</p> </div> </div>
Card Styles (card.component.css)
.card-container { border: 1px solid #e0e0e0; border-radius: 8px; margin: 1rem 0; overflow: hidden; } .card-header { padding: 1rem; background-color: #f5f5f5; display: flex; justify-content: space-between; align-items: center; cursor: pointer; } .card-content { padding: 0 1rem; /* Adjust padding to avoid jump on toggle */ } .card-footer { padding: 1rem; background-color: #fafafa; border-top: 1px solid #e0e0e0; } .toggle-icon { font-size: 1.2rem; }
Step 3: Reuse with Child Components
Since you have two child components inheriting from the base Card, they can directly leverage the animation without extra work. Here's an example for a Chart Card:
// chart-card.component.ts import { Component, Input } from '@angular/core'; import { CardComponent } from '../card/card.component'; @Component({ selector: 'app-chart-card', templateUrl: './chart-card.component.html', styleUrls: ['./chart-card.component.css'] }) export class ChartCardComponent extends CardComponent { @Input() chartData: any[]; // Child-specific input }
<!-- chart-card.component.html --> <app-card [headerTitle]="'Sales Overview'" [summaryText]="'Total: $12,450'"> <!-- Your chart component here --> <app-line-chart [data]="chartData"></app-line-chart> </app-card>
Key Optimizations & Customizations
- Adjust Animation Behavior: Modify the
animate()parameters (e.g.,'500ms ease-out') to match your app's design system. - Animate Footer Too: If you want the summary footer to slide with the content, move it inside the animated
card-contentdiv or add a separate trigger for it. - Accessibility: We added
role="button"andaria-expandedattributes to make the toggle keyboard-navigable. You can also addtabindex="0"and handlekeydownevents for Enter/Space keys. - Performance: Using
heighttransitions is straightforward, but for dynamic content, consider usingmax-heightwith a sufficiently high value (e.g.,max-height: 2000px) to avoid layout jumps.
Troubleshooting Tips
- If the animation has jumpy behavior: Ensure the
card-contenthas no margin (use padding instead) and that theoverflow: hiddenis properly applied. - Child components not inheriting state: Make sure you're extending the base class correctly and passing inputs through to the parent component.
内容的提问来源于stack exchange,提问作者Zerok

