如何使用(迷你变体)实现sidenav导航抽屉

Geo*_* C. 10 angular-material2 angular

角度材料2社区我需要你的帮助如何在角度材料2中制作像谷歌材料设计示例的迷你变体.

我尝试实现这一点,但我无法实现这一点

在此输入图像描述

我的代码到目前为止

  <!-- ===================================================================== -->
  <!-- SIDENAV && SIDENAV CONTAINER -->
  <!-- ===================================================================== -->
  <mat-sidenav-container>

    <mat-sidenav 
      #adminNavMenu 
      mode="side" 
      opened="true"
      style="min-width:50px; background: #F3F3F3;"
      class="shadow_right" autosize>

      <!-- MENU LEFT -->
      <app-admin-menu-left></app-admin-menu-left>

    </mat-sidenav>

   <mat-sidenav-container>
Run Code Online (Sandbox Code Playgroud)

应用程序管理员菜单,left.html

<mat-nav-list style="min-width:60px;">

  <mat-list-item *ngFor="let page of Menus"> 
    <a routerLink="{{page.link}}" routerLinkActive="active" 
      [routerLinkActiveOptions]="{exact:true}" matLine>
      <mat-icon class="home_icon collapse-icon vcenter" mat-list-icon>{{page.icon}}</mat-icon>
      <span *ngIf="!showFiller">
        {{page.name}}
      </span>
    </a>
  </mat-list-item>


</mat-nav-list>

<button  mat-icon-button (click)="showFiller = !showFiller" mat-raised-button>
  <mat-icon *ngIf="!showFiller">chevron_right</mat-icon>
  <mat-icon *ngIf="showFiller">chevron_left</mat-icon> 
</button>
Run Code Online (Sandbox Code Playgroud)

结束给了我这个意外的结果

在此输入图像描述

点击后查看迷你吧 在此输入图像描述

如您所见,有250 px的余量,mat-sidenav-content但我无法访问此元素.

在此输入图像描述

任何帮助解决这个问题都会很有用.

感谢名单

Geo*_* C. 19

我用这个解决方案传递了这个问题.如果这解决了你的问题让我知道,如果这不能解决你的问题请问我.

祝好运.

home.component.html

<div>

  <mat-sidenav-container>

    <mat-sidenav #adminNavMenu mode="side" opened="true" style="min-width:60px; background: #F3F3F3;" class="shadow_right" autosize>

      <!-- MENU LEFT -->
      <!-- MENU LEFT -->
      <app-admin-menu-left></app-admin-menu-left>

    </mat-sidenav>

    <!-- ================================================================= -->
    <!-- ************************* MAIN CONTAINER ************************ -->
    <!-- ================================================================= -->
    <mat-sidenav-content [@onSideNavChange]="sideNavState">
      <div class="main_container" fxLayout="column" fxLayoutGap="0px" style="height:100vh;">

        <!-- =============================================================== -->
        <!-- Your main content -->
        <!-- =============================================================== -->

      </div>
    </mat-sidenav-content>

  </mat-sidenav-container>


</div>
Run Code Online (Sandbox Code Playgroud)

home.component.ts

/**
 * George35mk
 */

import { Component, OnInit } from '@angular/core';
import { MatSidenav } from '@angular/material';
import { trigger, state, style, transition, animate } from '@angular/animations';

import { MediatorService } from '@app-services/mediator/mediator.service';


@Component({
  selector: 'app-admin-analytics',
  templateUrl: './admin-analytics.component.html',
  styleUrls: ['./admin-analytics.component.css'],
  animations: [
    trigger('onSideNavChange', [
      state('close',
        style({
          'margin-left': '60px'
        })
      ),
      state('open',
        style({
          'margin-left': '250px'
        })
      ),
      transition('close => open', animate('250ms ease-in')),
      transition('open => close', animate('250ms ease-in')),
    ]),

    trigger('onPageReady', [
      state('inactive',
        style({
          opacity: 0.4
        })
      ),
      state('active',
        style({
          opacity: 1
        })
      ),
      transition('inactive => active', animate('250ms ease-in')),
      transition('active => inactive', animate('250ms ease-in')),
    ])
  ]
})
export class HomeComponent implements OnInit {


  /**
   * Get the sidenav state.
   */
  sideNavState: string = this.mediator.getSideNavState;



  constructor(
    private mediator: MediatorService,
  ) { }

  ngOnInit() {


    // Subscribe on changes important.
    this.mediator.sideNavListener.subscribe( state => {
      this.sideNavState = state;
    });

  }


}
Run Code Online (Sandbox Code Playgroud)

mediator.service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';


@Injectable()
export class MediatorService {

  APP_VERSION: String = 'v8.3.1.36';

  // default value.
  // this variable track the value between sessions.
  private _sideState: any = 'open';

  /**
   * This is the mini variant solution with animations trick.
   */
  sideNavListener: any = new Subject();

  get sideNavState() {
    return this._sideState;
  }

  setSidenavState(state) {
    this._sideState = state;
  }


  constructor() {

    this.sideNavListener.subscribe( state => {
      this.setSidenavState(state);
    });


  }


}
Run Code Online (Sandbox Code Playgroud)

菜单left.component.html

<div class="sidenav_menu_left" 
    [@onSideNavChange]="sideNavState" 
    style="width:100%; height: 100vh;" 
    fxLayout="column" 
    [style.overflow]="overflowState">

    <p>Sidenav content left</p>

    <!-- this can toggle the sidenav -->
    <div fxFlex="100" (click)="toggleSideNav();" class="hoverble"></div>

</div>
Run Code Online (Sandbox Code Playgroud)

菜单left.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { MatSidenav } from '@angular/material';
import {trigger, state, style, transition, animate, keyframes, query, group} from '@angular/animations';


// Mediator: the main service, later this service is gonna have more generic use.
import { MediatorService } from '@app-services/mediator/mediator.service';
import { delay } from 'q';


@Component({
  selector: 'app-admin-menu-left',
  templateUrl: './admin-menu-left.component.html',
  styleUrls: ['./admin-menu-left.component.css'],
  animations: [

    // animate sidenave
    trigger('onSideNavChange', [
      state('close',
        style({
          width: '60px'
        })
      ),
      state('open',
        style({
          width: '250px'
        })
      ),
      transition('close => open', animate('250ms ease-in')),
      transition('open => close', animate('250ms ease-in')),

    ])

  ]
})
export class MenuLeftComponent implements OnInit {


  /**
   * Get the sidenav state,
   */
  sideNavState: string = this.mediator.sideNavState;


  overflowState: any = 'auto';

  constructor(
    private mediator: MediatorService
  ) {

  }

  ngOnInit() {

    this.mediator.sideNavListener.subscribe( state => {
      this.sideNavState = state;
    });

  }

  /**
   * On animation done.
   * @param x
   */
  animationEvent(x) {
    this.overflowState = 'auto';
  }

  /**
   * Toggle the sidenave state.
   *
   * Hides entire sidenav onclose.
   */
  setSideNavState() {
    this.mediator.toggle().then( snap => {
      console.log(snap);
    });
  }


  /**
   * Toggle, Open or close the sidenav.
   *
   * Set the sidenave state on mediator.
   */
  toggleSideNav() {

    switch (this.sideNavState) {

      case 'close':

        this.sideNavState = 'open';
        this.mediator.setSideNavState(this.sideNavState);

        setTimeout( () => {{
          this.sideNavText      = this.sideNavText === 'open' ? 'close' : 'open';
          this.sideNavIcon      = this.sideNavIcon === 'open' ? 'close' : 'open';
          this.sideNavCopyRight = this.sideNavCopyRight === 'open' ? 'close' : 'open';
        }}, 200);
      break;

      case 'open':
        this.sideNavText      = this.sideNavText === 'open' ? 'close' : 'open';
        this.sideNavIcon      = this.sideNavIcon === 'open' ? 'close' : 'open';
        this.sideNavCopyRight = this.sideNavCopyRight === 'open' ? 'close' : 'open';

        setTimeout( () => {{
          this.sideNavState = this.sideNavState === 'open' ? 'close' : 'open';
          this.mediator.setSideNavState(this.sideNavState);
        }}, 200);
      break;

      default:
        console.log('#6644');
        break;
    }

    this.overflowState = 'hidden';
  }

}
Run Code Online (Sandbox Code Playgroud)


San*_*ise 6

我已经为此挣扎了很多。解决方案比您想象的要简单得多……角度中的几乎所有东西都可以动画,我们可以用几行非常简单的动画代码来解决这个问题……

在名为 sidenav.animations.ts 的文件中,您将创建一个动画来为 <mat-sidenav> 的宽度设置 200px 到 60px 之间的动画

您将创建第二个动画来为 <mat-sidenav-content> 设置边距为 201px 和 61px 之间的动画。

./sidenav.animations.ts

 import {
  animate,
  state,
  style,
  transition,
  trigger,
} from '@angular/animations';

/*
 * animation: sideNaveAnimation
 * trigger: 'openClose'
 *
 * comments: sets the width of an element to 200px when 'open' and to 60px
 *   when closed.  Animates in between these two states over '0.3s'
 */

export const sideNavAnimation = trigger('openCloseSidenav', [
    // ...
    state('open', style({
      width: '200px',
    })),
    state('closed', style({
      width: '60px',
    })),
    transition('open <=> closed', [
      animate('0.3s')
    ]),
  ]);

/*
 * animation: sideNavContainerAnimation
 * trigger: 'openCloseSidenavContent'
 *
 * comments: Sets the margin-left to 201px when "open" and 61px when "closed".
 */

export const sideNavContainerAnimation = trigger('openCloseSidenavContent', [
    state('open', style({
      'margin-left': '201px',
    })),
    state('closed', style({
      'margin-left': '61px',
    })),
    transition('open <=> closed', [
      animate('0.3s')
    ]),
  ]);
Run Code Online (Sandbox Code Playgroud)

在你的 app.component.ts ...

您将导入这两个动画并在 animations 数组中使用它们,这将允许您在 app.component.html 中使用 sidenav.animations.ts('openCloseSidenav' 和 'openCloseSidenavContent')中定义的触发器

您将创建一个布尔值 (isOpen) 来跟踪 sidenav 处于哪个状态

您将创建一个名为 toggle() 的函数,该函数将在 true 和 false 之间切换变量 isOpen。按下 app.component.html 中的按钮将调用此函数

./app.component.ts 不要忘记将您的 MatSidenavModule、MatButtonsModule、MatIconModule、MatListModule 和 BrowserAnimationsModule 导入您的 app.module.ts 中,否则您将无法使用 <mat-sidenav> 或任何在你的 app.component.html 中的任何地方

import { Component } from '@angular/core';

//...

import { sideNavAnimation, sideNavContainerAnimation } from './sidenav.animations';

//...


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  animations: [sideNavAnimation, sideNavContainerAnimation]
})

export class AppComponent {

  isOpen = true;

  toggle() {
     this.isOpen = !this.isOpen;
   }

//...

}
Run Code Online (Sandbox Code Playgroud)

并在您的 app.component.html ... 您将使用放置在 sidenav 某处的按钮调用 toggle()。

您将在 <mat-sidenav> 上放置动画触发器:'openCloseSidenav',该表达式将选择元素应该是两个定义状态('open' 或 'closed',如 sidenav.animations.ts 中定义的那样)中的哪一个根据变量 isOpen 的状态在状态之间进行动画处理。

您将使用与上述相同的表达式在 <mat-sidenav-content> 上放置动画触发器:'openCloseSidenavContent'。

./app.component.html

<mat-sidenav-container>

  <mat-sidenav [@openCloseSidenav]="isOpen ? 'open' : 'closed'" mode="side" opened role="navigation">
    <mat-nav-list>
      <!-- Place nav links here -->

      <button type="button" aria-label="Toggle nav" mat-icon-button (click)="toggle()">
      <mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
      </button>

    </mat-nav-list>
  </mat-sidenav>

  <mat-sidenav-content [@openCloseSidenavContent]="isOpen ? 'open' : 'closed'">
    <router-outlet></router-outlet>
  </mat-sidenav-content>

</mat-sidenav-container>
Run Code Online (Sandbox Code Playgroud)

其余的你必须自己填写,我的 <mat-sidenav-list> 有如下所示的内容。

...我正在使用变量 isOpen 来决定是否应该显示图标旁边的文本..我很快就会将动画添加到 <mat-chip-list> 标签中,以使它们在切换时淡出()被调用并且 isOpen 发生变化,否则我会将动画时间缩短到 0.0 秒,以便它在两个状态之间立即捕捉...

...然而,即使标签中没有 *ngIf="isOpen",这也能正常工作......

    <a mat-list-item (click)="signOut()">
        <span  class="app-nav-list-icon">
          <mat-icon matListIcon class="app-nav-list-icon">
            <fa-icon icon="sign-out-alt"style="color: #808DE1;"></fa-icon>
          </mat-icon>
        </span>
        <mat-chip-list *ngIf="isOpen" style="padding-left: .5em;">
          <mat-chip>Logout</mat-chip>
        </mat-chip-list>
      </a>
Run Code Online (Sandbox Code Playgroud)

...这里最重要的是,简单的动画可用于控制应用程序各个方面的行为和外观...

访问https://angular.io/guide/animations了解有关其工作原理的更多详细信息...