UNPKG

bixi

Version:

企业级中后台前端解决方案

160 lines (144 loc) 5.08 kB
import { Injectable, Injector, OnDestroy, Optional } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; import { IBreadcrumb } from './layout.type'; export const LAYOUT = 'layout'; interface IOptions { breadFn?: (items: IBreadcrumb[]) => IBreadcrumb[]; } const uniqueElementsBy = (breads: IBreadcrumb[], fn: (bread1: IBreadcrumb, bread2: IBreadcrumb) => boolean) => breads.reduce((result: IBreadcrumb[], v: IBreadcrumb) => { if (!result.some((x: IBreadcrumb) => fn(v, x))) { // 判断是否重复 result.push(v); } return result; }, []); @Injectable({ providedIn: 'root' }) export class BixiLayoutService implements OnDestroy { openChange = new BehaviorSubject<boolean>(true); breadcrumb$ = new BehaviorSubject<IBreadcrumb[]>([]); menuVisible$ = new BehaviorSubject<boolean>(true); headerVisible$ = new BehaviorSubject<boolean>(true); // 这里记录路由切换时,组件加载时,传入的参数 options$ = new BehaviorSubject<IOptions>({}); routerChange = new Subscription(); constructor( private injector: Injector, private router: Router, private title: Title, @Optional() private i18n: TranslateService ) { this.routerChange = this.router.events .pipe(filter((e) => e instanceof NavigationEnd)) .subscribe(() => { this.updateBreads(); }); } private updateBreads() { let route = this.injector.get(ActivatedRoute); let titles: IBreadcrumb[] = []; while (route.firstChild) { route = route.firstChild; const data = (route.snapshot && route.snapshot.data) || {}; if (data.breadcrumbs) { if (typeof data.breadcrumbs === 'function') { const breadcrumbs = data.breadcrumbs(route); titles = [...titles, ...breadcrumbs]; } else if (Array.isArray(data.breadcrumbs)) { titles = [...titles, ...data.breadcrumbs]; } else { console.warn('route breadcrumbs 只支持 Array 和 function, 请查看路由配置'); } titles = titles.map((bread: IBreadcrumb) => { if (bread.titleI18n) { return { name: this.i18n.instant(bread.titleI18n), link: bread.link || bread.path }; } return bread; }); } else if (data.title || data.titleI18n) { if (this.i18n) { titles.push({ name: data.title ? data.title : this.i18n.instant(data.titleI18n), link: data.path }); } else { titles.push({ name: data.title, link: data.path }); } } else { // nothing } } this.breadcrumb$.next(uniqueElementsBy(this.formatBreakcrumb(titles), (bread1: IBreadcrumb, bread2: IBreadcrumb) => { return bread1.name === bread2.name && bread1.path === bread2.path && bread1.link === bread2.link; })); this.options$.next({}); } toggleMenu(open?: boolean) { if (open === undefined) { this.openChange.next(!this.openChange.value); } else { this.openChange.next(!!open); } } toggleHeader(show?: boolean) { if (show === undefined) { this.headerVisible$.next(!this.headerVisible$.value); } else { this.headerVisible$.next(!!show); } } private formatBreakcrumb(breads: IBreadcrumb[]) { const options = this.options$.value; if (typeof options.breadFn === 'function') { return options.breadFn(breads); } return breads; } setBreadcrumbs(breadFn: (items: IBreadcrumb[]) => IBreadcrumb[]) { // 由于 router 变化钩子函数在组件的 constructor 之后执行,这里为了保证 setBreadcrumbs 的时效性,使用定时器 setTimeout(() => { this.options$.next({ ...this.options$.value, breadFn }); this.updateBreads(); }); } private getByRoute(): string { let next = this.injector.get(ActivatedRoute); while (next.firstChild) next = next.firstChild; const data = (next.snapshot && next.snapshot.data) || {}; if (typeof data.breadcrumbs === 'function') { const breadcrumbs = data.breadcrumbs(next); data.title = breadcrumbs && breadcrumbs.length ? breadcrumbs[breadcrumbs.length - 1].name : ''; } if (data.titleI18n && this.i18n && !data.title) { data.title = this.i18n.instant(data.titleI18n); } return data.title; } setPageTitle(titleFn?: (breads: IBreadcrumb[]) => string) { if (typeof titleFn === 'function') { this.title.setTitle(titleFn(this.breadcrumb$.value)); return; } const title = this.getByRoute(); if (title) { this.title.setTitle(`${this.getByRoute()}`); } else { this.title.setTitle('Bixi'); } } ngOnDestroy(): void { this.routerChange.unsubscribe(); } }