-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(module:affix&anchor&back-top&avatar): add components to library (#…
…88) * feat(module:back-top): add `nz-back-top` component * feat(module:affix): add `nz-affix` component * feat(module:anchor): add `nz-anchor` component * feat(module:avatar): add `nz-avatar` component
- Loading branch information
1 parent
2bf24e0
commit 468e80b
Showing
50 changed files
with
1,956 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* tslint:disable:no-unused-variable */ | ||
import { async, ComponentFixture, TestBed, ComponentFixtureAutoDetect, fakeAsync, tick } from '@angular/core/testing'; | ||
import { Component, DebugElement } from '@angular/core'; | ||
import { By } from '@angular/platform-browser'; | ||
|
||
import { NzAffixModule } from './nz-affix.module'; | ||
import { NzScrollService } from "../core/scroll/nz-scroll.service"; | ||
import { NzAffixComponent } from "./nz-affix.component"; | ||
|
||
describe('Component:nz-affix', () => { | ||
|
||
let scrollSrv: MockNzScrollService; | ||
let fixture: ComponentFixture<TestAffixComponent>; | ||
let context: TestAffixComponent; | ||
let el: HTMLDivElement; | ||
let comp: NzAffixComponent; | ||
|
||
beforeEach(fakeAsync(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [NzAffixModule], | ||
declarations: [TestAffixComponent], | ||
providers: [ | ||
{ provide: NzScrollService, useClass: MockNzScrollService } | ||
] | ||
}).compileComponents(); | ||
|
||
fixture = TestBed.createComponent(TestAffixComponent); | ||
context = fixture.componentInstance; | ||
spyOn(context, 'onChange'); | ||
fixture.detectChanges(); | ||
el = fixture.nativeElement; | ||
comp = fixture.debugElement.query(By.css('nz-affix')).componentInstance as NzAffixComponent; | ||
tick(); | ||
})); | ||
|
||
it('should correctly initialize and attach to DOM', () => { | ||
expect(el.querySelectorAll('.ant-affix').length).toBe(1); | ||
}); | ||
|
||
}); | ||
|
||
@Component({ template: `<nz-affix [nzOffsetTop]="10" (nzChange)="onChange($event)"><button>Affix Button</button></nz-affix>` }) | ||
class TestAffixComponent { | ||
onChange(status: boolean) { | ||
return status; | ||
} | ||
} | ||
|
||
class MockNzScrollService { | ||
|
||
getOffset(el: Element): { top: number, left: number } { | ||
return { top: 0, left: 0 }; | ||
} | ||
|
||
getScroll(el?: Element | Window, top: boolean = true): number { | ||
return 0; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { | ||
Component, | ||
ViewEncapsulation, | ||
OnInit, | ||
Input, | ||
EventEmitter, | ||
Output, | ||
Renderer2, | ||
OnDestroy, | ||
ViewChild, | ||
ElementRef, | ||
HostBinding | ||
} from '@angular/core'; | ||
import { Observable } from 'rxjs/Observable'; | ||
import { Subscription } from 'rxjs/Subscription'; | ||
|
||
import { NzScrollService } from "../core/scroll/nz-scroll.service"; | ||
|
||
@Component({ | ||
selector: 'nz-affix', | ||
encapsulation: ViewEncapsulation.None, | ||
template: `<div #wrap><ng-content></ng-content></div>`, | ||
styleUrls: [ | ||
'./style/index.less', | ||
'./style/patch.less' | ||
] | ||
}) | ||
export class NzAffixComponent implements OnInit, OnDestroy { | ||
|
||
private scroll$: Subscription = null; | ||
private scrollWinInTarget$: Subscription = null; | ||
private target: Element = null; | ||
@ViewChild('wrap') private wrap: ElementRef; | ||
// 缓存固定状态 | ||
private fixed: boolean = false; | ||
// 原始位置 | ||
private orgOffset: { top: number, left: number }; | ||
|
||
@Input() | ||
set nzTarget(el: Element) { | ||
this.target = el; | ||
this.registerScrollEvent(); | ||
} | ||
|
||
@Input() nzOffsetTop: number = 0; | ||
|
||
@Input() nzOffsetBottom: number = 0; | ||
|
||
@Output() nzChange: EventEmitter<boolean> = new EventEmitter(); | ||
|
||
constructor(private scrollSrv: NzScrollService, private _el: ElementRef, private _renderer: Renderer2) { } | ||
|
||
ngOnInit(): void { | ||
if (!this.scroll$) this.registerScrollEvent(); | ||
} | ||
|
||
private getTarget(): Element | Window { | ||
return this.target || window; | ||
} | ||
|
||
private reCalculate() { | ||
let elOffset = this.scrollSrv.getOffset(this._el.nativeElement); | ||
this.orgOffset = { | ||
top: elOffset.top + this.scrollSrv.getScroll(this.getTarget()), | ||
left: elOffset.left + this.scrollSrv.getScroll(this.getTarget(), false) | ||
}; | ||
|
||
return this; | ||
} | ||
|
||
private process() { | ||
if (!this.orgOffset) this.reCalculate(); | ||
const containerScrollTop = this.scrollSrv.getScroll(this.getTarget()); | ||
let fixTop = this.getTarget() === window ? 0 : this.scrollSrv.getOffset(this.getTarget() as Element).top; | ||
let hasFixed = this.orgOffset.top - fixTop - containerScrollTop - this.nzOffsetTop <= 0; | ||
if (this.fixed === hasFixed) return; | ||
|
||
const wrapEl = this.wrap.nativeElement; | ||
wrapEl.classList[hasFixed ? 'add' : 'remove']('ant-affix'); | ||
if (hasFixed) { | ||
wrapEl.style.cssText = `top:${this.nzOffsetTop + fixTop}px;left:${this.orgOffset.left}px`; | ||
} else { | ||
wrapEl.style.cssText = ``; | ||
} | ||
|
||
this.fixed = hasFixed; | ||
this.nzChange.emit(hasFixed); | ||
} | ||
|
||
private removeListen() { | ||
if (this.scroll$) this.scroll$.unsubscribe(); | ||
if (this.scrollWinInTarget$) this.scrollWinInTarget$.unsubscribe(); | ||
} | ||
|
||
private registerScrollEvent() { | ||
this.removeListen(); | ||
this.reCalculate().process(); | ||
this.scroll$ = Observable.fromEvent(this.getTarget(), 'scroll') | ||
.throttleTime(50) | ||
.distinctUntilChanged() | ||
.subscribe(e => { | ||
this.process(); | ||
}); | ||
|
||
if (this.getTarget() !== window) { | ||
// 当 window 滚动位发生变动时,需要重新计算滚动容器 | ||
this.scrollWinInTarget$ = Observable.fromEvent(window, 'scroll') | ||
.throttleTime(50) | ||
.distinctUntilChanged() | ||
.subscribe(e => { | ||
this.orgOffset = null; | ||
this.fixed = false; | ||
}); | ||
} | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this.removeListen(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { NgModule } from '@angular/core'; | ||
import { CommonModule } from '@angular/common'; | ||
|
||
import { NzAffixComponent } from './nz-affix.component'; | ||
import { SCROLL_SERVICE_PROVIDER } from "../core/scroll/nz-scroll.service"; | ||
|
||
@NgModule({ | ||
declarations: [ NzAffixComponent ], | ||
exports : [ NzAffixComponent ], | ||
imports : [ CommonModule ], | ||
providers : [ SCROLL_SERVICE_PROVIDER ] | ||
}) | ||
export class NzAffixModule { | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
@import "../../style/themes/default"; | ||
|
||
.@{ant-prefix}-affix { | ||
position: fixed; | ||
z-index: @zindex-affix; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
nz-affix { | ||
display: block; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { | ||
Component, | ||
ViewEncapsulation, | ||
Input, | ||
TemplateRef, | ||
ContentChild, | ||
HostBinding, | ||
HostListener, | ||
ElementRef | ||
} from '@angular/core'; | ||
|
||
import { NzAnchorComponent } from './nz-anchor.component'; | ||
|
||
@Component({ | ||
selector: 'nz-link', | ||
encapsulation: ViewEncapsulation.None, | ||
template: ` | ||
<a (click)="goToClick($event)" href="{{nzHref}}" class="ant-anchor-link-title"> | ||
<span *ngIf="!nzTemplate">{{nzTitle}}</span> | ||
<ng-template *ngIf="nzTemplate" [ngTemplateOutlet]="nzTemplate"></ng-template> | ||
</a> | ||
<ng-content></ng-content> | ||
` | ||
}) | ||
export class NzAnchorLinkComponent { | ||
|
||
@Input() nzHref: string; | ||
|
||
@Input() nzTitle: string; | ||
|
||
@ContentChild('nzTemplate') nzTemplate: TemplateRef<any>; | ||
|
||
@HostBinding('class.ant-anchor-link') _nzAnchorLink = true; | ||
|
||
@HostBinding('class.ant-anchor-link-active') active: boolean = false; | ||
|
||
@HostListener('click') | ||
_onClick() { | ||
this._anchorComp.scrollTo(this); | ||
} | ||
|
||
constructor(public el: ElementRef, private _anchorComp: NzAnchorComponent) { | ||
this._anchorComp.add(this); | ||
} | ||
|
||
goToClick(e: Event) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
this._anchorComp.scrollTo(this); | ||
return false; | ||
} | ||
} |
Oops, something went wrong.