zoukankan      html  css  js  c++  java
  • 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('*',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: '您确认删除该项目吗?' }
        });
      }
    }
    View Code

    在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()
            }
          ]
        }
      ];
    }
    View Code

    定义路由

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

    建立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;
    }
    View Code

    修改一下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);
        });
      }
    }
    View Code

    Stagger使得在多个元素时候,动画交错开,而不是一起。

  • 相关阅读:
    函数式语言(老师作业)
    session/cookie
    Linux根目录下各个目录的功能介绍
    Navicat12安装文件和破解补丁
    正则表达式验证示例
    RequestDispatcher接口示例
    hello2部分源码解析
    Introduction of Servlet Filter
    关于hello1中的web.xml解析
    Annotation解释
  • 原文地址:https://www.cnblogs.com/starof/p/10359897.html
Copyright ? 2011-2022 开发猿


http://www.vxiaotou.com