Detailed explanation of Angular routing animation and advanced animation functions

Detailed explanation of Angular routing animation and advanced animation functions

1. Routing animation

Route animations require triggers to be specified in the host metadata. Be careful not to have too much animation, otherwise it will backfire.

Content comes first, guiding users to pay attention to certain content. Animation is just a supplement.

Define an entry animation and an exit animation in router.animate.ts.

Because entry and exit animations are used so frequently, there is an alias called :enter and :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%)'}))
    ]),
]);

Use route animation in 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: "Enterprise Collaboration Platform",
      desc: "This is an internal project",
      coverImg: "assets/images/covers/0.jpg"
    },
    {
      name: "Automated Testing Project",
      desc: "This is an internal project",
      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: 'New project' }
    });
    dialogRef.afterClosed().subscribe((result) => {
      console.log(result);
    });
  }

  lauchInviteDialog() {
    const dialogRef = this.dialog.open(InviteComponent);
  }

  launchUpdateDialog() {
    const dialogRef = this.dialog.open(NewProjectComponent, {
      data: { title: 'Edit Project' }
    });
  }

  lauchConfimDialog() {
    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      data: { title: 'Edit item', content: 'Are you sure you want to delete this item? ' }
    });
  }
}

Use route animation in 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: "New Task" }
    });
  }
  launchCopyTaskDialog() {
    const dialogRef = this.dialog.open(CopyTaskComponent, {
      data: { lists: this.lists }
    });
  }

  launchUpdateTaskDialog(task) {
    const dialogRef = this.dialog.open(NewTaskComponent, {
      data: { title: "Modify task", task: task }
    });
  }

  launchConfirmDialog() {
    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      data: { title: "Delete task list", content: "Are you sure you want to delete this task list?" }
    });
  }

  launchEditListDialog() {
    const dialogRef = this.dialog.open(NewTaskListComponent, {
      data: { title: "Change list name" }
    });
    dialogRef.afterClosed().subscribe(result => console.log(result));
  }
  launchNewListDialog() {
    const dialogRef = this.dialog.open(NewTaskListComponent, {
      data: { title: "New list name" }
    });
    dialogRef.afterClosed().subscribe(result => console.log(result));
  }
  lists = [
    {
      id: 1,
      name: "To Do",
      tasks:
        {
          id: 1,
          desc: "Task 1: Go to Starbucks to buy coffee",
          completed: true,
          priority: 3,
          owner:
            id: 1,
            name: "Zhang San",
            avatar: "avatars:svg-11"
          },
          dueDate: new Date(),
          reminder: new Date()
        },
        {
          id: 2,
          desc: "Task 1: Complete the PPT assignment assigned by the boss",
          completed: false,
          priority: 2,
          owner:
            id: 2,
            name: "Li Si",
            avatar: "avatars:svg-12"
          },
          dueDate: new Date()
        }
      ]
    },
    {
      id: 2,
      name: "In Progress",
      tasks:
        {
          id: 1,
          desc: "Task 3: Project Code Review",
          completed: false,
          priority: 1,
          owner:
            id: 1,
            name: "Wang Wu",
            avatar: "avatars:svg-13"
          },
          dueDate: new Date()
        },
        {
          id: 2,
          desc: "Task 1: Develop a project plan",
          completed: false,
          priority: 2,
          owner:
            id: 2,
            name: "Li Si",
            avatar: "avatars:svg-12"
          },
          dueDate: new Date()
        }
      ]
    }
  ];
}

Defining Routes

<mat-list-item [routerLink]="['/project']"> 
    <mat-icon mat-list-icon svgIcon="projects"></mat-icon>
    <h4 mat-line>Project Home</h4>
    <p mat-line mat-subheader> View all your projects</p>
  </mat-list-item>
  <mat-list-item [routerLink]="['/task']"> 
    <mat-icon mat-list-icon svgIcon="projects"></mat-icon>
    <h4 mat-line>Task Home Page</h4>
    <p mat-line mat-subheader> View all your projects</p>
  </mat-list-item>

Note: Be sure to use the HostBinding format.

2. Group

Used to animate a group of transformations simultaneously

group([animate(...),animate(...)...]) receives an array, in which multiple animations are written.

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 is used by the parent node to find the child node and apply the animation to the selected element. Very powerful.

Stagger specifies that there are multiple elements that satisfy the Query, and there is an interval between each animation.

Let's take an example: when creating a new project, create two new projects at the same time. The animations of the two new projects will be generated in sequence, and the second one will start after the first one is completed.

Create list.animate.ts

The entry animation is hidden first, and a 1s animation is made at an interval of 1000s through stagger.

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 }), //Add optional to true, the following state animations are optional 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 })
    ])
  ]);

Use in project_list

The query animation is usually applied together with *ngFor, and a div layer is needed outside.

<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>

Modify the corresponding css

// :host{
// display: flex;
// flex-direction: row;
// flex-wrap: wrap;
// }

//Change host to div
.container{
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}

Modify the 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 //The first step is to import listAnimation
  ]
})
export class ProjectListComponent implements OnInit {
  @HostBinding('@routeAnim') state;

  //The second step is to transform the array and add id
  projects = [
    {
      id:1,
      name: "Enterprise Collaboration Platform",
      desc: "This is an internal project",
      coverImg: "assets/images/covers/0.jpg"
    },
    {
      id:2,
      name: "Automated Testing Project",
      desc: "This is an internal project",
      coverImg: "assets/images/covers/2.jpg"
    }
  ];
  constructor(private dialog: MatDialog) { }

  ngOnInit() { }

  //Step 3, hard code openNewProjectDialog() when adding new elements {
    // this.dialog.open(NewProjectComponent,{data:'this is a dialog'});
    const dialogRef = this.dialog.open(NewProjectComponent, {
      data: { title: 'New project' }
    });
    dialogRef.afterClosed().subscribe((result) => {
      console.log(result);
      this.projects = [...this.projects, 
        {id:3,name:'A new project',desc:'This is a new project',coverImg:"assets/images/covers/3.jpg"},
        {id:4,name:'Another new project',desc:'This is another new project',coverImg:"assets/images/covers/4.jpg"}]
    });
  }

  lauchInviteDialog() {
    const dialogRef = this.dialog.open(InviteComponent);
  }

  launchUpdateDialog() {
    const dialogRef = this.dialog.open(NewProjectComponent, {
      data: { title: 'Edit Project' }
    });
  }

  //Step 4: Modify and delete the project lauchConfimDialog(project) {
    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      data: { title: 'Delete item', content: 'Are you sure you want to delete this item? ' }
    });
    dialogRef.afterClosed().subscribe(result=>{
      console.log(result);
      this.projects=this.projects.filter(p=>p.id!=project.id);
    });
  }
}

Stagger makes it so that when there are multiple elements, the animations are staggered instead of all at once.

The above is a detailed explanation of Angular routing animation and advanced animation functions. For more information about Angular routing animation and advanced animation functions, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Detailed explanation of Angular routing sub-routes
  • Detailed explanation of Angular routing basics
  • Angular multi-level routing to achieve login page jump (novice tutorial)
  • Usage of default routing in angular

<<:  Detailed explanation of Nginx current limiting configuration

>>:  MySQL 5.7.21 decompressed version of the tutorial to restore data through the historical data directory

Recommend

Detailed tutorial on running selenium+chromedriver on the server

1. Introduction I want to use selenium to scrape ...

Installation, configuration and use of process daemon supervisor in Linux

Supervisor is a very good daemon management tool....

Why can't I see the access interface for Docker Tomcat?

Question: Is the origin server unable to find a r...

How to add shortcut commands in Xshell

As a useful terminal emulator, Xshell is often us...

Example of creating a virtual host based on Apache port

apache: create virtual host based on port Take cr...

Stealing data using CSS in Firefox

0x00 Introduction A few months ago, I found a vul...

Some Linux file permission management methods you may not know

Why do we need permission management? 1. Computer...

How to communicate between WIN10 system and Docker internal container IP

1. After installing the Windows version of Docker...

Explanation of the problem of selecting MySQL storage time type

The datetime type is usually used to store time i...

Let's learn about the MySQL storage engine

Table of contents Preface 1. MySQL main storage e...

MySQL limit performance analysis and optimization

1. Conclusion Syntax: limit offset, rows Conclusi...

Example steps for using AntV X6 with Vue.js

Table of contents 0x0 Introduction 0x1 Installati...

A brief discussion on VUE uni-app's commonly used APIs

Table of contents 1. Routing and page jump 2. Int...

How to use JSX in Vue

What is JSX JSX is a syntax extension of Javascri...