angular - 从另一个组件控制有角度的材料垫抽屉
问题描述
我有两个组件,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">
©{{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 组件(通过路由器插座动态加载)中的垫子抽屉的打开和关闭。
解决方案
抽屉存在的组件
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();
}
这对我有用。更多细节
推荐阅读
- python - 是否有 PyObject 类的实现允许您正确覆盖魔术方法?
- wordpress - 带有逗号分隔字符串的 WordPress WP_Query
- regex - 拉字符串值
- asp.net - 如何将 ngOninit 与异步数据一起使用
- gtk - 同步调度到 GTK+ 的主线程
- python - Python line_num 打印行号仅输出最后一个行号
- alloy - Alloy :限制字符串字段的值
- c++ - Cmake 找不到 Boost(缺少 python)(找到版本 1.73.0)
- javascript - 无法获取动态生成的 id
- visual-studio - 在本地机器上运行解决方案的问题(VS 2017)