这种样式修改的方式限制太多,且比较麻烦,因此又通过对sidebar-nav进行修改,来实现该功能。第二版。
1、默认的左右布局
2、切换后的上下布局
1、布局切换服务类,用于通知需要改变布局的模块去改变样式
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs/Subject'; @Injectable() export class LayoutChangeService { constructor() {} private Source = new Subject
(); Status$ = this.Source.asObservable(); /** *@函数名称:layoutChange *@参数:message 字符类型参数 *@作用:接受布局切换的变化,用户通知各个模块做相应的样式改变 *@date 2018/5/16 */ layoutChange(message: any) { const msg = JSON.parse(message); this.Source.next(msg); this.setLayout(msg); } /** * 获取布局方式的缓存 true为上下布局 false为左右布局 * @returns {boolean} */ get getLayout() { const layout = localStorage.getItem('layoutMode'); if (layout === 'true') { return true; } else { return false; } } /** * 设置默认的布局方式缓存 * @param val */ setLayout(val) { localStorage.setItem('layoutMode', val); } }
2、新增HeaderLayoutComponent ,增加切换的入口,切换布局时通知其他需要修改的模块去改变样式。
import { Component, HostListener } from '@angular/core'; import { LayoutChangeService } from '@core/layout/layoutChange.service'; @Component({ selector: 'header-layout', template: ` {{(status ? '左右布局' : '上下布局') | translate }} `, host: { '[class.d-block]': 'true', }, }) export class HeaderLayoutComponent { constructor(public changeService: LayoutChangeService) {} status = this.changeService.getLayout; @HostListener('window:resize') _resize() { // this.status = screenfull.isFullscreen; } @HostListener('click', ['$event']) _changeTheme(e) { this.changeService.layoutChange(!this.status); this.status = !this.status; } }
3、修改需要改变样式的部分(注意事项:通过俩层dom的click事件来动态改变topMenu的高度,达到显示和隐藏topMenu的效果,且解决topMenu遮罩层覆盖其他模块问题)
1)菜单dom,处理自己的样式变化,大部分样式修改都在该模块完成。
import { Component, ElementRef, AfterViewInit, ViewChild, Renderer2, } from '@angular/core'; import { NzMessageService } from 'ng-zorro-antd'; import { SettingsService } from '@delon/theme'; import { TabChangeService } from '@core/tabChange/tabChange.service'; import { LayoutChangeService } from '@core/layout/layoutChange.service'; import { Subscription } from 'rxjs/Subscription'; import { AppUtil } from '@core/util/util.service'; import { StartupService } from '@core/startup/startup.service'; @Component({ selector: 'app-sidebar', templateUrl: './sidebar.component.html', }) export class SidebarComponent implements AfterViewInit { subscription: Subscription; layoutStatus = this.layoutService.getLayout; @ViewChild('sidebarNav') sidebarNav; constructor( public settings: SettingsService, public msgSrv: NzMessageService, public changeService: TabChangeService, public layoutService: LayoutChangeService, public el: ElementRef, public util: AppUtil, public renderer2: Renderer2, public startupService: StartupService, ) { this.subscription = layoutService.Status$.subscribe(message => { // 获取当前dashboard的名称 和切换的tab页相互校验 this.layoutStatus = message; this.setLayout(message); }); } ngAfterViewInit() { this.setLayout(this.layoutService.getLayout); } // 设置样式 setLayout(direction) { // border-left: 3px solid #349ac0; this.hideULBorder(direction); const el = this.el.nativeElement; this.setStyles(el.querySelectorAll('ul'), direction); this.setStyles(el.querySelectorAll('li'), direction); // 处理小屏模式下 文字隐藏导致切换后头部菜单无法显示 this.setCollapsed(); this.setTopMenuShow(); } onclick() { setTimeout(() => this.setTopMenuShow()); } // 隐藏ul的有边框 hideULBorder(direction) { const el = this.el.nativeElement; const boardRight = direction ? '1px solid #18191d' : ''; el.querySelector('ul').style['border-right'] = boardRight; } // 设置屏幕为非pad setCollapsed() { if (this.settings.layout.collapsed && this.layoutStatus) { this.settings.setLayout('collapsed', !this.settings.layout.collapsed); } } // 设置样式属性值 setStyles(dom, direction) { const len = dom.length; // 设置默认的样式 切换后改变样式 let float = 'none'; let display = ''; let absolute = ''; let top = ''; let backgroundColor = ''; if (direction) { float = 'left'; display = 'none'; absolute = 'absolute'; top = '60px'; backgroundColor = this.util.getColor('background'); } // 循环改变样式 for (let i = 0; i < len; i++) { const singleItem = dom[i]; // 设置ui和li的左悬浮样式 singleItem.style['float'] = float; singleItem.style['list-style-type'] = 'none'; const tagName = singleItem.tagName; // 隐藏图标 const img = singleItem.querySelector('i'); if (img) { // TODO 是否显示图标 && this.settings.layout.collapsed img.style['display'] = display; } if (tagName === 'LI') { // 隐藏导航菜单项 const textDom = singleItem.querySelector('span'); if (textDom && textDom.innerText === '导航菜单') { singleItem.style['display'] = display; } // 处理有二级菜单节点的样式 const ULINLI = singleItem.querySelector('ul'); if (ULINLI) { ULINLI.style['position'] = absolute; ULINLI.style['top'] = top; ULINLI.style['background-color'] = backgroundColor; } } } } // 隐藏二级菜单 setTopMenuShow() { this.setTreeMenuHeight(true); } // 二级菜单显示 setTopMenuHide() { this.setTreeMenuHeight(false); } // 设置topMenu的高度 防止覆盖到模块中 setTreeMenuHeight(show) { const me = this; const dom = this.el.nativeElement; if (me.layoutStatus) { if (!show && !dom.style.height) { dom.style.height = '60px'; } else if (show && dom.style.height) { dom.style.height = ''; } } else { if (show && dom.style.height) { dom.style.height = ''; } } } /** *@函数名称:callDestroy *@参数:val 组件传递的参数 *@作用:给服务传递切换信息 *@date 2018/5/16 */ callDestroy(val) { const value = { title: val.text, url: val.link, }; this.changeService.tabChange(JSON.stringify(value)); // 切换将topMeun隐藏 this.setTopMenuHide(); } }
2)默认布局LayoutDefaultComponent,点击该层dom时,将topMenu隐藏,防止遮住内容显示区域,
import { Component, OnDestroy, ViewChild } from '@angular/core'; import { Router, NavigationEnd, RouteConfigLoadStart, NavigationError, } from '@angular/router'; import { NzMessageService, NzModalService } from 'ng-zorro-antd'; import { ScrollService, MenuService, SettingsService } from '@delon/theme'; import { TabChangeService } from '@core/tabChange/tabChange.service'; import { LayoutChangeService } from '@core/layout/layoutChange.service'; import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'layout-default', templateUrl: './default.component.html', }) export class LayoutDefaultComponent implements OnDestroy { isFetching = false; subscription: Subscription; @ViewChild('appSidebar') appSidebar; constructor( router: Router, scroll: ScrollService, private _message: NzMessageService, public menuSrv: MenuService, public settings: SettingsService, public changeService: TabChangeService, public layoutService: LayoutChangeService, ) { // scroll to top in change page router.events.subscribe(evt => { if (!this.isFetching && evt instanceof RouteConfigLoadStart) { this.isFetching = true; } if (evt instanceof NavigationError) { this.isFetching = false; _message.error(`无法加载${evt.url}路由`, { nzDuration: 1000 * 3 }); return; } if (!(evt instanceof NavigationEnd)) { return; } setTimeout(() => { scroll.scrollToTop(); this.isFetching = false; }, 100); }); this.subscription = layoutService.Status$.subscribe(message => { // 获取当前dashboard的名称 和切换的tab页相互校验 this.layoutStatus = message; }); } /** *@函数名称:tabChange *@参数:val获取组件传过来的值,传递下去 *@作用:给服务传递切换信息 *@date 2018/5/16 */ tabChange(val): void { const value = { title: val.title, url: val.url, }; this.changeService.tabChange(JSON.stringify(value)); } layoutStatus = this.layoutService.getLayout; ngOnDestroy() { this.subscription.unsubscribe(); } /** * 点击将topMenu隐藏 */ onclick(e) { this.appSidebar.setTopMenuHide(); } }
3)需要覆盖的样式
//处理动态切换menu布局样式覆盖 .aside-top { float: left; margin-left: 20px; margin-top: 0 !important; z-index: 30; width: @top-menu-width; left: 170px; background-color: transparent; } // 覆盖组件样式,有边框 .aside-top::after { border-right: 0 solid @primary-color !important; } // 覆盖样式,左边高度处理 .content-top { margin-left: 27px; } // 动态路由左边距离处理 .reuse-tab-fixed-top { left: 27px !important; } // 样式覆盖 .aside-inner-top { float: left; margin-left: 20px; width: 100%; } // 样式覆盖 .ul-nav { padding-top: 12px !important; } // 样式覆盖 .header-search-top { padding-left: @top-menu-Rightwidth; }