Angular动画——路由动画及高阶动画函数
一、路由动画路由动画需要在host元数据中指定触发器。动画注意不要过多,否则适得其反。 内容优先,引导用户去注意到某个内容。动画只是辅助手段。 定义一个进场动画,一个离场动画。 因为进场动画和离场动画用的特别频繁,有一个别名叫:enter和:leave。 import { trigger,state,transition,style,animate} from ‘@angular/animations‘; export const slideToRight = trigger(‘routeAnim‘,[ state(‘void‘,style({‘position‘:‘fixed‘,‘width‘:‘100%‘,‘height‘:‘100%‘})),state(‘*‘,‘height‘:‘80%‘})),transition(‘void => *‘,[ style({transform:‘translateX(-100%)‘}),animate(‘.5s ease-in-out‘,style({transform:‘translateX(0)‘})) ]),transition(‘* => void‘,[ style({transform:‘translateX(0)‘}),style({transform:‘translateX(100%)‘})) ]),]); 在project-list中使用路由动画。 import { Component,OnInit,HostBinding } from "@angular/core"; import { MatDialog } from "@angular/material"; import { NewProjectComponent } from "../new-project/new-project.component"; import { InviteComponent } from ‘../invite/invite.component‘; import { ConfirmDialogComponent } from ‘../../shared/confirm-dialog/confirm-dialog.component‘; import {slideToRight} from ‘../../animate/router.animate‘ @Component({ selector: "app-project-list",templateUrl: "./project-list.component.html",styleUrls: ["./project-list.component.scss"],animations:[ slideToRight ] }) export class ProjectListComponent implements OnInit { @HostBinding(‘@routeAnim‘) state; projects = [ { name: "企业协作平台",desc: "这是一个企业内部项目",coverImg: "assets/images/covers/0.jpg" },{ name: "自动化测试项目",coverImg: "assets/images/covers/2.jpg" } ]; constructor(private dialog: MatDialog) { } ngOnInit() { } openNewProjectDialog() { // this.dialog.open(NewProjectComponent,{data:‘this is a dialog‘}); const dialogRef = this.dialog.open(NewProjectComponent,{ data: { title: ‘新建项目‘ } }); dialogRef.afterClosed().subscribe((result) => { console.log(result); }); } lauchInviteDialog() { const dialogRef = this.dialog.open(InviteComponent); } lauchUpdateDialog() { const dialogRef = this.dialog.open(NewProjectComponent,{ data: { title: ‘编辑项目‘ } }); } lauchConfimDialog() { const dialogRef = this.dialog.open(ConfirmDialogComponent,{ data: { title: ‘编辑项目‘,content: ‘您确认删除该项目吗?‘ } }); } } 在task-home中使用路由动画。 import { Component,HostBinding } from "@angular/core"; import { NewTaskComponent } from "../new-task/new-task.component"; import { MatDialog } from "@angular/material"; import { CopyTaskComponent } from "../copy-task/copy-task.component"; import { ConfirmDialogComponent } from "../../shared/confirm-dialog/confirm-dialog.component"; import { NewTaskListComponent } from "../new-task-list/new-task-list.component"; import {slideToRight} from ‘../../animate/router.animate‘; @Component({ selector: "app-task-home",templateUrl: "./task-home.component.html",styleUrls: ["./task-home.component.scss"],animations:[ slideToRight ] }) export class TaskHomeComponent implements OnInit { constructor(private dialog: MatDialog) {} @HostBinding(‘@routeAnim‘) state; ngOnInit() {} launchNewTaskDialog() { // this.dialog.open(NewTaskComponent); const dialogRef = this.dialog.open(NewTaskComponent,{ data: { title: "新建任务" } }); } lauchCopyTaskDialog() { const dialogRef = this.dialog.open(CopyTaskComponent,{ data: { lists: this.lists } }); } launchUpdateTaskDialog(task) { const dialogRef = this.dialog.open(NewTaskComponent,{ data: { title: "修改任务",task: task } }); } launchConfirmDialog() { const dialogRef = this.dialog.open(ConfirmDialogComponent,{ data: { title: "删除任务列表",content: "您确定要删除该任务列表吗?" } }); } launchEditListDialog() { const dialogRef = this.dialog.open(NewTaskListComponent,{ data: { title: "更改列表名称" } }); dialogRef.afterClosed().subscribe(result => console.log(result)); } launchNewListDialog() { const dialogRef = this.dialog.open(NewTaskListComponent,{ data: { title: "新建列表名称" } }); dialogRef.afterClosed().subscribe(result => console.log(result)); } lists = [ { id: 1,name: "待办",tasks: [ { id: 1,desc: "任务一: 去星巴克买咖啡",completed: true,priority: 3,owner: { id: 1,name: "张三",avatar: "avatars:svg-11" },dueDate: new Date(),reminder: new Date() },{ id: 2,desc: "任务一: 完成老板布置的PPT作业",completed: false,priority: 2,owner: { id: 2,name: "李四",avatar: "avatars:svg-12" },dueDate: new Date() } ] },{ id: 2,name: "进行中",desc: "任务三: 项目代码评审",priority: 1,name: "王五",avatar: "avatars:svg-13" },dueDate: new Date() },desc: "任务一: 制定项目计划",dueDate: new Date() } ] } ]; } 定义路由 <mat-list-item [routerLink]="[‘/project‘]"> <mat-icon mat-list-icon svgIcon="projects"></mat-icon> <h4 mat-line>项目首页</h4> <p mat-line mat-subheader> 查看您的所有项目</p> </mat-list-item> <mat-list-item [routerLink]="[‘/task‘]"> <mat-icon mat-list-icon svgIcon="projects"></mat-icon> <h4 mat-line>任务首页</h4> <p mat-line mat-subheader> 查看您的所有项目</p> </mat-list-item>? 注意:一定要用HostBinding形式。 二、Group用于同时进行一组动画变换 group([animate(...),animate(...)...])接收一个数组,数组里写多个动画。 import { trigger,animate,group} from ‘@angular/animations‘; export const slideToRight = trigger(‘routeAnim‘,transition(‘:enter‘,[ style({transform:‘translateX(-100%)‘,opacity:‘0‘}),group([ animate(‘.5s ease-in-out‘,style({transform:‘translateX(0)‘})),animate(‘.3s ease-in‘,style({opacity:1})) ]) ]),transition(‘:leave‘,[ style({transform:‘translateX(0)‘,opacity:‘1‘}),style({transform:‘translateX(100%)‘})),style({opacity:0})) ]) ]),]); 三、Query & StaggerQuery用于父节点寻找子节点,把动画应用到选中元素。非常强大。 Stagger指定有多个满足Query的元素,每个的动画之间有间隔。 做一个示例:新建的时候同时新建2个项目,两个新建出的项目的动画依次产生,第一个完成后才开始第二个。 建立list.animate.ts? 进场动画,先隐藏起来,通过stagger间隔1000s做一个1s的动画。 import { trigger,query,animation,stagger} from ‘@angular/animations‘; export const listAnimation = trigger(‘listAnim‘,[ transition(‘* => *‘,[ query(‘:enter‘,style({opacity: 0}),{ optional: true }),//加入optional为true,后面的状态动画都是可选的 query(‘:enter‘,stagger(1000,[ animate(‘1s‘,style({opacity: 1})) ]),{ optional: true }),query(‘:leave‘,style({opacity: 1}),{ optional: true }),style({opacity: 0})) ]),{ optional: true }) ]) ]); 在project_list中使用 应用query动画一般都是跟*ngFor在一起的,需要外面套一层div。 <div class="container" [@listAnim]="projects.length"> <app-project-item *ngFor="let project of projects" [item]="project" class="card" (onInvite)="lauchInviteDialog()" (onEdit)="lauchUpdateDialog()" (onDelete)="lauchConfimDialog(project)"> </app-project-item> </div> <button class="ab-buttonmad-fab fab-button" mat-fab type="button" (click)="openNewProjectDialog()"> <mat-icon>add</mat-icon> </button> 修改对应的css // :host{ // display: flex; // flex-direction: row; // flex-wrap: wrap; // } //把host改为div .container{ display: flex; flex-direction: row; flex-wrap: wrap; } 修改一下component import { Component,HostBinding } from "@angular/core"; import { MatDialog } from "@angular/material"; import { NewProjectComponent } from "../new-project/new-project.component"; import { InviteComponent } from ‘../invite/invite.component‘; import { ConfirmDialogComponent } from ‘../../shared/confirm-dialog/confirm-dialog.component‘; import {slideToRight} from ‘../../animate/router.animate‘ import { listAnimation } from ‘../../animate/list.animate‘; import { projection } from ‘@angular/core/src/render3‘; @Component({ selector: "app-project-list",animations:[ slideToRight,listAnimation //第一步,导入listAnimation ] }) export class ProjectListComponent implements OnInit { @HostBinding(‘@routeAnim‘) state; //第二步,改造一下数组,加id projects = [ { id:1,name: "企业协作平台",{ id:2,name: "自动化测试项目",coverImg: "assets/images/covers/2.jpg" } ]; constructor(private dialog: MatDialog) { } ngOnInit() { } //第三步,新增元素时hard code一下 openNewProjectDialog() { // this.dialog.open(NewProjectComponent,{ data: { title: ‘新建项目‘ } }); dialogRef.afterClosed().subscribe((result) => { console.log(result); this.projects = [...this.projects,{id:3,name:‘一个新项目‘,desc:‘这是一个新项目‘,coverImg:"assets/images/covers/3.jpg"},{id:4,name:‘又一个新项目‘,desc:‘这是又一个新项目‘,coverImg:"assets/images/covers/4.jpg"}] }); } lauchInviteDialog() { const dialogRef = this.dialog.open(InviteComponent); } lauchUpdateDialog() { const dialogRef = this.dialog.open(NewProjectComponent,{ data: { title: ‘编辑项目‘ } }); } //第四步,改造一下删除项目 lauchConfimDialog(project) { const dialogRef = this.dialog.open(ConfirmDialogComponent,{ data: { title: ‘删除项目‘,content: ‘您确认删除该项目吗?‘ } }); dialogRef.afterClosed().subscribe(result=>{ console.log(result); this.projects=this.projects.filter(p=>p.id!=project.id); }); } } Stagger使得在多个元素时候,动画交错开,而不是一起。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |