评论

收藏

[JavaScript] 详解Angular路由动画及高阶动画函数

开发技术 开发技术 发布于:2021-06-29 10:25 | 阅读数:246 | 评论:0

一、路由动画
  路由动画需要在host元数据中指定触发器。动画注意不要过多,否则适得其反。
  内容优先,引导用户去注意到某个内容。动画只是辅助手段。
  在router.animate.ts中定义一个进场动画,一个离场动画。
  因为进场动画和离场动画用的特别频繁,有一个别名叫: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('*',style({'position':'fixed','width':'100%','height':'80%'})),
  transition('void => *',[
    style({transform:'translateX(-100%)'}),
    animate('.5s ease-in-out', style({transform:'translateX(0)'}))
  ]),
  transition('* => void',[
    style({transform:'translateX(0)'}),
    animate('.5s ease-in-out', 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: "自动化测试项目",
    desc: "这是一个企业内部项目",
    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, OnInit , 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: "进行中",
    tasks: [
    {
      id: 1,
      desc: "任务三: 项目代码评审",
      completed: false,
      priority: 1,
      owner: {
      id: 1,
      name: "王五",
      avatar: "avatars:svg-13"
      },
      dueDate: new Date()
    },
    {
      id: 2,
      desc: "任务一: 制定项目计划",
      completed: false,
      priority: 2,
      owner: {
      id: 2,
      name: "李四",
      avatar: "avatars:svg-12"
      },
      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, state, transition, style, animate, group} from '@angular/animations';
export const slideToRight = trigger('routeAnim',[
  state('void',style({'position':'fixed','width':'100%','height':'80%'})),
  state('*',style({'position':'fixed','width':'100%','height':'80%'})),
  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'}),
    group([
      animate('.5s ease-in-out', style({transform:'translateX(100%)'})),
      animate('.3s ease-in', style({opacity:0}))
    ])
  ]),
]);
三、Query & Stagger
  Query用于父节点寻找子节点,把动画应用到选中元素。非常强大。
  Stagger指定有多个满足Query的元素,每个的动画之间有间隔。
  做一个示例:新建的时候同时新建2个项目,两个新建出的项目的动画依次产生,第一个完成后才开始第二个。
DSC0000.jpg

  建立list.animate.ts
  进场动画,先隐藏起来,通过stagger间隔1000s做一个1s的动画。
import { trigger, state, transition, style, animate, 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 }),
    query(':leave', stagger(1000, [
    animate('1s', 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, 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'
import { listAnimation } from '../../animate/list.animate';
import { projection } from '@angular/core/src/render3';
@Component({
  selector: "app-project-list",
  templateUrl: "./project-list.component.html",
  styleUrls: ["./project-list.component.scss"],
  animations:[
  slideToRight,listAnimation  //第一步,导入listAnimation
  ]
})
export class ProjectListComponent implements OnInit {
  @HostBinding('@routeAnim') state;
  //第二步,改造一下数组,加id
  projects = [
  {
    id:1,
    name: "企业协作平台",
    desc: "这是一个企业内部项目",
    coverImg: "assets/images/covers/0.jpg"
  },
  {
    id:2,
    name: "自动化测试项目",
    desc: "这是一个企业内部项目",
    coverImg: "assets/images/covers/2.jpg"
  }
  ];
  constructor(private dialog: MatDialog) { }
  ngOnInit() { }
  //第三步,新增元素时hard code一下
  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);
    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使得在多个元素时候,动画交错开,而不是一起。
  以上就是详解Angular路由动画及高阶动画函数的详细内容,更多关于Angular路由动画及高阶动画函数的资料请关注脚本之家其它相关文章!

关注下面的标签,发现更多相似文章