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

目录

一、路由动画二、Group三、Query & Stagger

一、路由动画

路由动画需要在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个项目,两个新建出的项目的动画依次产生,第一个完成后才开始第二个。

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

建立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路由动画及高阶动画函数的资料请关注其它相关文章!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容