希望菜单项可以放在顶部
之前使用样式修改修改过第一版,后来发现问题较多,而且样式修改起来特别麻烦,因此通过对sidebar-nav的修改满足需求。
1、主要是通过修改sidebar-nav.component.js,实现新的nav组件
// =========LAYOUTS========= @import './../../../styles/theme'; @import './../../../styles/index'; .ad-nav-head-div { float: left; margin-left: 20px; width: 100%; height: 60px; } .ad-nav-head { float: left; list-style-type: none; margin-top: -10px; border-right: 1px solid @content-heading-border; .ad-nav-li-head { float: left; list-style-type: none; border-left: 0 solid transparent; border-bottom: 0 solid transparent; transition: border-bottom-color 0.4s ease; .ad-nav-li-hend-ui { float: left; list-style-type: none; position: absolute; top: 48px; background-color: @aside-bg; } } .ad-nav__-head-selected { background-repeat: no-repeat; background-size: 100% 100%; height: 100%; background-position: center center; background-image: url('../../../assets/img/nav/nav-selected-bg.png'); } .ad-nav__-head-selected > a { color: @blue-color2; } } .ad-nav-li-head-hidden { display: none !important; }
import { Component, OnInit, HostListener, ChangeDetectorRef, ElementRef, Renderer2, Input, Output, EventEmitter, OnDestroy, AfterViewInit, } from '@angular/core'; import { LayoutChangeService } from '@core/layout/layoutChange.service'; import { Router, NavigationEnd } from '@angular/router'; import { LocationStrategy } from '@angular/common'; import { MenuService, SettingsService, Menu } from '@delon/theme'; import { filter } from 'rxjs/operators'; import { Subscription } from 'rxjs/Subscription'; /** @type {?} */ const SHOWCLS = 'ad-nav__floating-show'; /** @type {?} */ const FLOATINGCLS = 'ad-nav__floating'; /*头部selected样式*/ const HEDNSELECTED = 'ad-nav__-head-selected'; /*左树选中样式*/ const LEFTSELECTED = 'ad-nav__selected'; @Component({ selector: 'app-header-nav', template: ` <div [ngClass]="{'ad-nav-head-div' : loyout}"> <ul class="ad-nav" [ngClass]="{'ad-nav-head': loyout}"> <ng-container *ngFor="let group of list"> <ng-template [ngIf]="group._hidden !== true"> <li class="ad-nav__item ad-nav__group-title" [ngClass]="{'ad-nav-li-head': loyout, 'ad-nav-li-head-hidden': group.text === '导航菜单' ? true : false}" *ngIf="group.group"><span>{{ group.text }}</span></li> <ng-container *ngFor="let child1 of group.children"> <li *ngIf="child1._hidden !== true" routerLinkActive="{{routerLinkActive}}" [ngClass]="{'ad-nav-li-head': loyout}" [routerLinkActiveOptions]="{exact: child1.linkExact}" class="ad-nav__item" [class.ad-nav__open]="child1._open"> <a *ngIf="child1._type === 1" (click)="onSelect(child1)" [routerLink]="child1.link" [target]="child1.target"> <i *ngIf="!settings.layout.collapsed" [hidden]="loyout" class="{{ child1.icon }}"></i> <nz-tooltip *ngIf="settings.layout.collapsed" nzPlacement="right" [nzTitle]="child1.text"> <span nz-tooltip> <i class="{{ child1.icon }}"></i> </span> </nz-tooltip> <span>{{ child1.text }}</span> </a> <a *ngIf="child1._type === 2" href="{{ child1.externalLink }}" target="{{child1.target}}" data-type="external"> <i *ngIf="!settings.layout.collapsed" [hidden]="loyout" class="{{ child1.icon }}"></i> <nz-tooltip *ngIf="settings.layout.collapsed" nzPlacement="right" [nzTitle]="child1.text"> <span nz-tooltip> <i class="{{ child1.icon }}"></i> </span></nz-tooltip> <span>{{ child1.text }}</span> </a> <a *ngIf="child1._type === 3" class="ad-nav__sub-title" (mouseleave)="toggleOpen(child1, false)" (click)="toggleOpenFun(child1)" (mouseenter)="showSubMenu($event, child1, true)"> <i [hidden]="loyout && !settings.layout.collapsed" class="{{ child1.icon }}"></i> <span>{{ child1.text }}</span> </a> <div *ngIf="child1.badge" title="{{child1.badge}}" class="badge badge-{{child1.badge_status}}" [class.badge-dot]="child1.badge_dot"><em>{{child1.badge}}</em></div> <ul *ngIf="child1._type === 3" [ngClass]="{'ad-nav-li-hend-ui': loyout}" (mouseenter)="checkPosition(child1, true)" (mouseleave)="checkPosition(child1, false)" class="ad-nav ad-nav__sub ad-nav__depth{{child1._depth}}"> <ng-container *ngFor="let child2 of child1.children"> <li *ngIf="child2._hidden !== true" routerLinkActive="{{routerLinkActive}}" [routerLinkActiveOptions]="{exact: child2.linkExact}" class="ad-nav__item" [class.ad-nav__open]="child2._open"> <a *ngIf="child2._type === 1" (click)="onSelect(child2)" [routerLink]="child2.link" [target]="child2.target">{{ child2.text}} </a> <a *ngIf="child2._type === 2" href="{{ child2.externalLink }}" target="{{ child2.target }}" data-type="external">{{ child2.text }} </a> <a *ngIf="child2._type === 3" class="ad-nav__sub-title" (click)="toggleOpenFun(child2)"> {{ child2.text}} </a> <div *ngIf="child2.badge" title="{{child2.badge}}" class="badge badge-{{child2.badge_status}}" [class.badge-dot]="child2.badge_dot"><em>{{child2.badge}}</em></div> <ul [ngClass]="{'ad-nav-li-hend-ui': loyout}" (mouseenter)="checkPosition(child2, true)" (mouseleave)="checkPosition(child2, false)" *ngIf="child2._type=== 3"class="ad-nav ad-nav__sub ad-nav__depth{{child2._depth}}"> <ng-container *ngFor="let child3 of child2.children"> <li *ngIf="child3._hidden !== true" routerLinkActive="{{routerLinkActive}}" [routerLinkActiveOptions]="{exact: child3.linkExact}" class="ad-nav__item" [class.ad-nav__open]="child3._open"> <a *ngIf="child3._type === 1" (click)="onSelect(child3)" [routerLink]="child3.link" [target]="child3.target">{{ child3.text}} </a> <a *ngIf="child3._type === 2" href="{{ child3.externalLink }}" target="{{ child3.target }}" data-type="external">{{ child3.text }}</a> <div *ngIf="child3.badge" title="{{child3.badge}}" class="badge badge-{{child3.badge_status}}" [class.badge-dot]="child3.badge_dot"><em>{{child3.badge}}</em></div> </li> </ng-container> </ul> </li> </ng-container> </ul> </li> </ng-container> </ng-template> </ng-container> </ul> </div> `, styleUrls: ['./header.nav.Component.less'], }) // extends SidebarNavComponent export class HeaderNavComponent implements OnInit, OnDestroy, AfterViewInit { constructor( public menuSrv: MenuService, public settings: SettingsService, public router: Router, public locationStrategy: LocationStrategy, public render: Renderer2, public cd: ChangeDetectorRef, public el: ElementRef, public layoutService: LayoutChangeService, ) { this.subscription = layoutService.Status$.subscribe(message => { // 获取当前的布局状态 this.loyout = message; this.initCollapsed(); this.setRouterLinkActive(); this.initSidebar('init'); }); } subscription: Subscription; public loyout = this.layoutService.getLayout; bodyEl: any; list = []; doc = document; @Input() autoCloseUnderPad = true; @Output('select') select = new EventEmitter(); rootEl = this.el.nativeElement; private change$: any; floatingEl: HTMLDivElement; private routerLinkActive: any = this.initRouterLinkActive(); private route$; private sidebar$; // 确定光标是否在下拉菜单上面 private isOnUl = false; // 监听切换ipad按钮事件 @HostListener('document:click', ['$event.target']) onClick() { this.hideAll(); } // propDecorators = { // autoCloseUnderPad: [{ type: Input }], // select: [{ type: Output }], // onClick: [{type: HostListener, args: ['document:click', ['$event.target']]}] // }; /** * 对选中样式进行初始化 */ public initRouterLinkActive() { this.routerLinkActive = this.loyout ? HEDNSELECTED : LEFTSELECTED; } /** * 切换时交替设置选中的样式 */ private setRouterLinkActive() { this.initRouterLinkActive(); let oldSelectDom; let delClassName; let addClassName; if (this.loyout) { addClassName = HEDNSELECTED; delClassName = LEFTSELECTED; oldSelectDom = this.rootEl.querySelector('.' + LEFTSELECTED); } else { addClassName = LEFTSELECTED; delClassName = HEDNSELECTED; oldSelectDom = this.rootEl.querySelector('.' + HEDNSELECTED); } this.render.addClass(oldSelectDom, addClassName); this.render.removeClass(oldSelectDom, delClassName); } ngOnInit() { const me = this; this.bodyEl = this.doc.querySelector('body'); this.menuSrv.openedByUrl(this.router.url); this.genFloatingContainer(); this.change$ = /** @type {?} */ (this.menuSrv.change.subscribe(function( res, ) { me.list = res; me.cd.detectChanges(); })); this.installUnderPad(); this.initRouterLinkActive(); } ngAfterViewInit() { this.initCollapsed(); this.sidebar$ = this.bodyEl.querySelector('app-sidebar'); this.initSidebar('init'); } /** * 处理当ipad场景是 menu在上面需要把ipad按钮隐藏 */ initCollapsed() { if (this.settings.layout.collapsed && this.loyout) { this.settings.setLayout('collapsed', !this.settings.layout.collapsed); } } /** * 处理在顶部的高度 避免遮挡tip * @param type init show hide */ initSidebar(type) { const me = this; const dom = me.sidebar$ || this.bodyEl.querySelector('app-sidebar'); if (me.loyout) { switch (type) { case 'show': if (dom.style.height !== '') { dom.style.height = ''; } break; case 'hide': if (dom.style.height === '') { dom.style.height = '60px'; } break; default: if (dom.style.height === '') { dom.style.height = '60px'; } } } else { if (dom.style.height !== '') { dom.style.height = ''; } } } /** * 设置app-sidebar高度 将app-sidebar显示出来 */ showSidebar() { this.initSidebar('show'); } /** * 设置app-sidebar高度 将app-sidebar隐藏 */ hideSidebar() { this.initSidebar('hide'); } floatingAreaClickHandle(e) { e.stopPropagation(); /** @type {?} */ const linkNode = /** @type {?} */ (e.target); if (linkNode.nodeName !== 'A') { return false; } /** @type {?} */ let url = linkNode.getAttribute('href'); if (url && url.startsWith('#')) { url = url.slice(1); } if (linkNode.dataset['type'] === 'external') { return true; } /** @type {?} */ const baseHerf = this.locationStrategy.getBaseHref(); if (baseHerf) { url = url.slice(baseHerf.length); } this.router.navigateByUrl(url); this.onSelect(this.menuSrv.getPathByUrl(url).pop()); this.hideAll(); e.preventDefault(); return false; } clearFloatingContainer() { if (!this.floatingEl) { return; } this.floatingEl.removeEventListener( 'click', this.floatingAreaClickHandle.bind(this), ); // fix ie: https://github.com/cipchk/delon/issues/52 if (this.floatingEl.hasOwnProperty('remove')) { this.floatingEl.remove(); } else if (this.floatingEl.parentNode) { this.floatingEl.parentNode.removeChild(this.floatingEl); } } genFloatingContainer() { this.clearFloatingContainer(); this.floatingEl = this.render.createElement('div'); this.floatingEl.classList.add(FLOATINGCLS + '-container'); this.floatingEl.addEventListener( 'click', this.floatingAreaClickHandle.bind(this), false, ); this.bodyEl.appendChild(this.floatingEl); } genSubNode(linkNode, item) { /** @type {?} */ const id = '_sidebar-nav-' + item['__id']; /** @type {?} */ const node = /** @type {?} */ (linkNode.nextElementSibling.cloneNode(true)); node.id = id; node.classList.add(FLOATINGCLS); node.addEventListener( 'mouseleave', function() { node.classList.remove(SHOWCLS); }, false, ); this.floatingEl.appendChild(node); return node; } hideAll() { /** @type {?} */ const allNode = this.floatingEl.querySelectorAll('.' + FLOATINGCLS); for (let i = 0; i < allNode.length; i++) { allNode[i].classList.remove(SHOWCLS); } } calPos(linkNode, node) { /** @type {?} */ const rect = linkNode.getBoundingClientRect(); /** @type {?} */ const scrollTop = Math.max( this.doc.documentElement.scrollTop, this.bodyEl.scrollTop, ); /** @type {?} */ const docHeight = Math.max( this.doc.documentElement.clientHeight, this.bodyEl.clientHeight, ); /** @type {?} */ let offsetHeight = 0; if (docHeight < rect.top + node.clientHeight) { offsetHeight = rect.top + node.clientHeight - docHeight; } node.style.top = rect.top + scrollTop - offsetHeight + 'px'; node.style.left = rect.right + 5 + 'px'; } /** * ipad 产品下 鼠标放在图标上显示菜单 * @param e * @param item * @param type */ showSubMenu(e, item, type) { if (this.loyout) { this.toggleOpen(item, type); return; } if (this.settings.layout.collapsed !== true) { return; } e.preventDefault(); /** @type {?} */ const linkNode = /** @type {?} */ (e.target); this.genFloatingContainer(); /** @type {?} */ const subNode = this.genSubNode(/** @type {?} */ (linkNode), item); this.hideAll(); subNode.classList.add(SHOWCLS); this.calPos(/** @type {?} */ (linkNode), subNode); } /** * 对外接口 * @param item */ onSelect(item) { this.select.emit(item); } /** * 判断是否在下来菜单上 */ checkPosition(item, type) { if (this.loyout) { this.isOnUl = type; if (!type) { this.toggleOpen(item, type); } } } toggleOpen(item, type) { if (this.loyout) { // 鼠标在menu上 将menu显示出来 setTimeout(() => { if (this.isOnUl) { return; } this.toggleOpenHead(item, type); }, 300); } } /** * 处理头部显示隐藏 * @param item * @param type */ toggleOpenHead(item, type) { if (type) { this.showSidebar(); } else { this.hideSidebar(); } this.menuSrv.visit(function(i, p) { if (i !== item) { i['_open'] = false; } }); /** @type {?} */ let pItem = item['__parent']; while (pItem) { pItem._open = true; pItem = pItem.__parent; } item._open = type; this.cd.markForCheck(); } /** * * @param item */ toggleOpenFun(item) { if (this.loyout) { return; } this.menuSrv.visit(function(i, p) { if (i !== item) { i['_open'] = false; } }); /** @type {?} */ let pItem = item['__parent']; while (pItem) { pItem._open = true; pItem = pItem.__parent; } item._open = !item._open; this.cd.markForCheck(); } ngOnDestroy() { this.change$.unsubscribe(); this.subscription.unsubscribe(); if (this.route$) { this.route$.unsubscribe(); } this.clearFloatingContainer(); } installUnderPad() { const me = this; if (!this.autoCloseUnderPad) return; this.route$ = /** @type {?} */ (this.router.events .pipe( filter(function(e) { return e instanceof NavigationEnd; }), ) .subscribe(function(s) { return me.underPad(); })); this.underPad(); } underPad() { const me = this; if (window.innerWidth < 992 && !this.settings.layout.collapsed) { setTimeout(function() { return me.settings.setLayout('collapsed', true); }); } } }