首页 > 解决方案 > 从另一个组件控制有角度的材料垫抽屉

问题描述

我有两个组件,AppNav 组件和 Machines 组件。AppNav 组件具有工具栏和 sidenav。我还在 AppNav 的工具栏上放置了一个过滤器按钮。在机器组件中有一个垫子抽屉,在单击 AppNav 工具栏中的过滤器按钮后需要切换它。问题是我不知道如何让两者沟通。Machines 组件不是 AppNav 组件的直接子组件,因为我通过放置在 AppNav 的 sidenav 内容中的路由器插座加载其他组件(机器等)。

从下面看组件:

DrawerService(我想创建它以减轻我的挫败感)

import { Injectable } from '@angular/core';
import { MatDrawer } from '@angular/material';

@Injectable({
    providedIn: 'root'
})
export class DrawerService {
    private drawer: MatDrawer;

    /**
     * setDrawer
     */
    public setDrawer(flyout: MatDrawer) {
        this.drawer = flyout;
    }

    /**
     * open
     */
    public open() {
        return this.drawer.open();
    }

    /**
     * close
     */
    public close() {
        return this.drawer.close();
    }

    /**
     * toggle
     */
    public toggle(): void {
        this.drawer.toggle();
    }
}

机器组件 (machines.component.ts)

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

@Component({
    selector: 'app-machines',
    templateUrl: './machines.component.html',
    styleUrls: ['./machines.component.sass']
})
export class Machines implements OnInit {

    constructor() { }

    ngOnInit() {
    }

}

机器 html (machines.component.html)

<mat-drawer-container
    fxFlexFill>
    <mat-drawer 
        mode="side"
        opened
        position="end"
        #flyout
        class="mat-elevation-z3"
        [style.width]="'200px'">

        <mat-toolbar>
            <span>Filter</span>

            <span fxFlex></span>

            <mat-icon 
                svgIcon="close"
                (click)="flyout.toggle()"></mat-icon>
        </mat-toolbar>

        <mat-list>
            <mat-list-item>01</mat-list-item>
            <mat-list-item>02</mat-list-item>
            <mat-list-item>03</mat-list-item>
            <mat-list-item>04</mat-list-item>
        </mat-list>
    </mat-drawer>
    <mat-drawer-content>
        <div>
            Lorem ipsum, dolor sit amet consectetur adipisicing elit. Saepe, id assumenda ratione quaerat at itaque dolorem sit ipsam, modi nam voluptatem nisi expedita quis possimus ea a sed neque? Iure!
        </div>
    </mat-drawer-content>
</mat-drawer-container>

AppNav 组件 (app-nav.component.ts)

import { Component, ViewChild, ViewChildren } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ThemeService } from '../services/theme.service';
import { DrawerService } from '../services/drawer.service';
import { MatDrawer } from '@angular/material';

@Component({
    selector: 'app-nav',
    templateUrl: './nav.component.html',
    styleUrls: ['./nav.component.sass']
})
export class AppNav {
    yearTodate: number = new Date().getFullYear();
    isDarkTheme: Observable<boolean>;
    links: Array<Object>;

    isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
    .pipe(
        map(result => result.matches)
    );

    @ViewChildren('flyout') public flyout: MatDrawer;

    constructor(
        private breakpointObserver: BreakpointObserver,
        private drawerService: DrawerService,
        private themeService: ThemeService) {}

    ngOnInit() {
        this.isDarkTheme = this.themeService.isDarkTheme;
        this.links = this.linksArray;
        this.drawerService.setDrawer(this.flyout);
    }

    toggleDarkTheme(checked: boolean) {
        this.themeService.setDarkTheme(checked);
    }

    toggleFlyout () {
        this.drawerService.toggle();
    }

    linksArray = [

        {
            route: "/dashboard",
            icon: "ballot",
            name: "Dashboard"
        },

        {
            route: "/vehicles",
            icon: "car",
            name: "Vehicles"
        }
    ]

}

AppNav html (app-nav.component.html)

<div
    [ngClass]="{'dark-theme': isDarkTheme | async}"
    fxLayout="column" 
    fxLayoutAlign="center center"
    fxFlexFill
    class="mat-app-background"
    style="position: relative">
    <mat-sidenav-container class="sidenav-container">
        <mat-sidenav
            #drawer
            class="sidenav mat-elevation-z3"
            fixedInViewport="true"
            [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
            [mode]="(isHandset$ | async) ? 'over' : 'side'"
            [opened]="!(isHandset$ | async)"
            fxLayout="column">

            <mat-nav-list>
                <a 
                    mat-list-item
                    routerLink="{{link.route}}"
                    *ngFor="let link of links">
                    <mat-icon svgIcon="{{link.icon}}"></mat-icon>
                    <span fxFlex="5"></span>
                    <span>{{link.name}}</span> 
                </a>
            </mat-nav-list>

            <span fxFlex></span>

            <mat-nav-list>
                <a 
                    mat-list-item
                    routerLink="/login">
                    <mat-icon svgIcon="login"></mat-icon>
                    <span fxFlex="5"></span>
                    <span>Login</span> 
                </a>
            </mat-nav-list>

            <mat-divider></mat-divider>

            <small 
                style="padding: 16px">
                &copy;{{yearTodate}} MotionPlus
            </small>
        </mat-sidenav>

        <mat-sidenav-content
            fxLayout="column">
            <mat-toolbar 
                color="primary">
                <button
                    type="button"
                    aria-label="Toggle sidenav"
                    mat-icon-button
                    (click)="drawer.toggle()"
                    *ngIf="isHandset$ | async">
                    <mat-icon 
                        aria-label="Side nav toggle icon"
                        svgIcon="menu">
                        <!-- menu -->
                    </mat-icon>
                </button>

                <span>MotionPlus</span>

                <span fxFlex></span>

                <button 
                    mat-icon-button
                    (click)="toggleFlyout()">
                    <mat-icon svgIcon="filter-variant"></mat-icon>
                </button>

                <button 
                    mat-icon-button
                    [matMenuTriggerFor]="bucket">
                    <mat-icon
                        svgIcon="format-color-fill"></mat-icon>
                </button>

                <mat-menu
                    #bucket="matMenu">
                    <button 
                        mat-menu-item
                        (click)="toggleDarkTheme(true)"
                        fxLayout="column"
                        fxLayoutAlign="center center">
                        <span
                            style="
                                background: purple; 
                                width: 42px; 
                                height: 42px; 
                                border-radius: 50%">
                        </span>
                    </button>

                    <button 
                        mat-menu-item
                        (click)="toggleDarkTheme(false)"
                        fxLayout="column"
                        fxLayoutAlign="center center">
                        <span
                            style="
                                background: yellow; 
                                width: 42px; 
                                height: 42px; 
                                border-radius: 50%">
                        </span>
                    </button>
                </mat-menu>
            </mat-toolbar>
            <!-- Add Content Here -->
            <div
                style="padding: 0 24px;"
                fxFlex>
                <router-outlet></router-outlet>
            </div>
        </mat-sidenav-content>
    </mat-sidenav-container>
</div>

指出我如何实现这一目标的正确方向。我想从 AppNav 组件控制 Machines 组件(通过路由器插座动态加载)中的垫子抽屉的打开和关闭。

标签: angularangular-materialangular6

解决方案


抽屉存在的组件

export class DashboardComponent implements OnInit {

    @ViewChild('drawer') public drawer: MatDrawer;

    ngOnInit() {
        this.toolbarService.setDrawer(this.drawer);
    }

}

带有切换按钮的组件。这是带有抽屉的组件的子组件:

export class PageToolbarComponent implements OnInit {

    toggleDrawer() {
        this.toolbarService.toggle();
    }

}

共享服务:

private drawer: MatDrawer;

setDrawer(drawer: MatDrawer) {
    this.drawer = drawer;
}

toggle(): void {
    this.drawer.toggle();
}

这对我有用。更多细节


推荐阅读