Skip to content

Commit 254b429

Browse files
authored
feat(module:anchor): sync new properties (#7494)
1 parent f423850 commit 254b429

File tree

13 files changed

+225
-7
lines changed

13 files changed

+225
-7
lines changed

components/anchor/anchor-link.component.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ import { NzAnchorComponent } from './anchor.component';
2727
exportAs: 'nzLink',
2828
preserveWhitespaces: false,
2929
template: `
30-
<a #linkTitle (click)="goToClick($event)" href="{{ nzHref }}" class="ant-anchor-link-title" title="{{ titleStr }}">
30+
<a
31+
#linkTitle
32+
class="ant-anchor-link-title"
33+
[href]="nzHref"
34+
[title]="titleStr"
35+
[target]="nzTarget"
36+
(click)="goToClick($event)"
37+
>
3138
<span *ngIf="titleStr; else titleTpl || nzTemplate">{{ titleStr }}</span>
3239
</a>
3340
<ng-content></ng-content>
@@ -37,6 +44,7 @@ import { NzAnchorComponent } from './anchor.component';
3744
})
3845
export class NzAnchorLinkComponent implements OnInit, OnDestroy {
3946
@Input() nzHref = '#';
47+
@Input() nzTarget?: string;
4048

4149
titleStr: string | null = '';
4250
titleTpl?: TemplateRef<NzSafeAny>;

components/anchor/anchor.component.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,23 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
9292
@WithConfig<number>()
9393
nzOffsetTop?: number = undefined;
9494

95+
@Input()
96+
@InputNumber(undefined)
97+
@WithConfig<number>()
98+
nzTargetOffset?: number = undefined;
99+
95100
@Input() nzContainer?: string | HTMLElement;
101+
@Input() nzCurrentAnchor?: string;
96102

97103
@Output() readonly nzClick = new EventEmitter<string>();
104+
@Output() readonly nzChange = new EventEmitter<string>();
98105
@Output() readonly nzScroll = new EventEmitter<NzAnchorLinkComponent>();
99106

100107
visible = false;
101108
wrapperStyle: NgStyleInterface = { 'max-height': '100vh' };
102109

103110
container?: HTMLElement | Window;
111+
activeLink?: string;
104112

105113
private links: NzAnchorLinkComponent[] = [];
106114
private animating = false;
@@ -160,7 +168,8 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
160168
}
161169

162170
const sections: Section[] = [];
163-
const scope = (this.nzOffsetTop || 0) + this.nzBounds;
171+
const offsetTop = this.nzTargetOffset ? this.nzTargetOffset : this.nzOffsetTop || 0;
172+
const scope = offsetTop + this.nzBounds;
164173
this.links.forEach(comp => {
165174
const sharpLinkMatch = sharpMatcherRegx.exec(comp.nzHref.toString());
166175
if (!sharpLinkMatch) {
@@ -195,11 +204,23 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
195204
});
196205
}
197206

207+
private setActive(comp?: NzAnchorLinkComponent): void {
208+
const originalActiveLink = this.activeLink;
209+
const targetComp = (this.nzCurrentAnchor && this.links.find(n => n.nzHref === this.nzCurrentAnchor)) || comp;
210+
if (!targetComp) return;
211+
212+
targetComp.setActive();
213+
const linkNode = targetComp.getLinkTitleElement();
214+
this.ink.nativeElement.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
215+
this.activeLink = (comp || targetComp).nzHref;
216+
if (originalActiveLink !== this.activeLink) {
217+
this.nzChange.emit(this.activeLink);
218+
}
219+
}
220+
198221
private handleActive(comp: NzAnchorLinkComponent): void {
199222
this.clearActive();
200-
comp.setActive();
201-
const linkNode = comp.getLinkTitleElement();
202-
this.ink.nativeElement.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
223+
this.setActive(comp);
203224
this.visible = true;
204225
this.setVisible();
205226
this.nzScroll.emit(comp);
@@ -226,7 +247,8 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
226247
this.animating = true;
227248
const containerScrollTop = this.scrollSrv.getScroll(this.getContainer());
228249
const elOffsetTop = getOffsetTop(el, this.getContainer());
229-
const targetScrollTop = containerScrollTop + elOffsetTop - (this.nzOffsetTop || 0);
250+
let targetScrollTop = containerScrollTop + elOffsetTop;
251+
targetScrollTop -= this.nzTargetOffset !== undefined ? this.nzTargetOffset : this.nzOffsetTop || 0;
230252
this.scrollSrv.scrollTo(this.getContainer(), targetScrollTop, {
231253
callback: () => {
232254
this.animating = false;
@@ -237,7 +259,7 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
237259
}
238260

239261
ngOnChanges(changes: SimpleChanges): void {
240-
const { nzOffsetTop, nzContainer } = changes;
262+
const { nzOffsetTop, nzContainer, nzCurrentAnchor } = changes;
241263
if (nzOffsetTop) {
242264
this.wrapperStyle = {
243265
'max-height': `calc(100vh - ${this.nzOffsetTop}px)`
@@ -248,5 +270,8 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
248270
this.container = typeof container === 'string' ? this.doc.querySelector(container) : container;
249271
this.registerScrollEvent();
250272
}
273+
if (nzCurrentAnchor) {
274+
this.setActive();
275+
}
251276
}
252277
}

components/anchor/anchor.spec.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ describe('anchor', () => {
2626
fixture.detectChanges();
2727
page = new PageObject();
2828
spyOn(context, '_scroll');
29+
spyOn(context, '_change');
2930
srv = TestBed.inject(NzScrollService);
3031
});
3132
afterEach(() => context.comp.ngOnDestroy());
@@ -131,6 +132,18 @@ describe('anchor', () => {
131132
});
132133
});
133134

135+
describe('[nzCurrentAnchor]', () => {
136+
it('customize the anchor highlight', () => {
137+
context.nzCurrentAnchor = '#basic';
138+
fixture.detectChanges();
139+
const linkList = dl.queryAll(By.css('.ant-anchor-link'));
140+
expect(linkList.length).toBeGreaterThan(0);
141+
const activeLink = linkList.find(n => (n.nativeElement as HTMLDivElement).getAttribute('nzhref') === '#basic')!;
142+
expect(activeLink).toBeTruthy();
143+
expect((activeLink.nativeElement as HTMLDivElement).classList).toContain('ant-anchor-link-active');
144+
});
145+
});
146+
134147
describe('[nzShowInkInFixed]', () => {
135148
beforeEach(() => {
136149
context.nzAffix = false;
@@ -169,6 +182,30 @@ describe('anchor', () => {
169182
});
170183
});
171184

185+
describe('(nzChange)', () => {
186+
it('should emit nzChange when click a link', fakeAsync(() => {
187+
spyOn(srv, 'scrollTo').and.callFake((_containerEl, _targetTopValue = 0, options = {}) => {
188+
if (options.callback) {
189+
options.callback();
190+
}
191+
});
192+
expect(context._change).not.toHaveBeenCalled();
193+
page.to('#basic-target');
194+
expect(context._change).toHaveBeenCalled();
195+
}));
196+
it('should emit nzChange when scrolling to the anchor', (done: () => void) => {
197+
spyOn(context, '_change');
198+
expect(context._change).not.toHaveBeenCalled();
199+
page.scrollTo();
200+
setTimeout(() => {
201+
const inkNode = page.getEl('.ant-anchor-ink-ball');
202+
expect(+inkNode.style.top!.replace('px', '')).toBeGreaterThan(0);
203+
expect(context._change).toHaveBeenCalled();
204+
done();
205+
}, throttleTime);
206+
});
207+
});
208+
172209
it('(nzClick)', () => {
173210
spyOn(context, '_click');
174211
expect(context._click).not.toHaveBeenCalled();
@@ -233,9 +270,12 @@ describe('anchor', () => {
233270
[nzBounds]="nzBounds"
234271
[nzShowInkInFixed]="nzShowInkInFixed"
235272
[nzOffsetTop]="nzOffsetTop"
273+
[nzTargetOffset]="nzTargetOffset"
236274
[nzContainer]="nzContainer"
275+
[nzCurrentAnchor]="nzCurrentAnchor"
237276
(nzClick)="_click($event)"
238277
(nzScroll)="_scroll($event)"
278+
(nzChange)="_change($event)"
239279
>
240280
<nz-link nzHref="#何时使用" nzTitle="何时使用"></nz-link>
241281
<nz-link nzHref="#basic" nzTitle="Basic demo"></nz-link>
@@ -288,8 +328,11 @@ export class TestComponent {
288328
nzAffix = true;
289329
nzBounds = 5;
290330
nzOffsetTop = 0;
331+
nzTargetOffset?: number;
291332
nzShowInkInFixed = false;
292333
nzContainer: any = null;
334+
nzCurrentAnchor?: string;
293335
_click() {}
336+
_change() {}
294337
_scroll() {}
295338
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
order: 4
3+
title:
4+
zh-CN: 自定义锚点高亮
5+
en-US: Customize the anchor highlight
6+
---
7+
8+
## zh-CN
9+
10+
自定义锚点高亮。
11+
12+
## en-US
13+
14+
Customize the anchor highlight.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'nz-demo-anchor-customize-highlight',
5+
template: `
6+
<nz-anchor nzCurrentAnchor="#components-anchor-demo-static">
7+
<nz-link nzHref="#components-anchor-demo-basic" nzTitle="Basic demo"></nz-link>
8+
<nz-link nzHref="#components-anchor-demo-static" nzTitle="Static demo"></nz-link>
9+
<nz-link nzHref="#api" nzTitle="API">
10+
<nz-link nzHref="#nz-anchor" nzTitle="nz-anchor"></nz-link>
11+
<nz-link nzHref="#nz-link" nzTitle="nz-link"></nz-link>
12+
</nz-link>
13+
</nz-anchor>
14+
`
15+
})
16+
export class NzDemoAnchorCustomizeHighlightComponent {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
order: 6
3+
title:
4+
zh-CN: 监听锚点链接改变
5+
en-US: Listening for anchor link change
6+
---
7+
8+
## zh-CN
9+
10+
监听锚点链接改变
11+
12+
## en-US
13+
14+
Listening for anchor link change.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'nz-demo-anchor-on-change',
5+
template: `
6+
<nz-anchor (nzChange)="handleChange($event)">
7+
<nz-link nzHref="#components-anchor-demo-basic" nzTitle="Basic demo"></nz-link>
8+
<nz-link nzHref="#components-anchor-demo-static" nzTitle="Static demo"></nz-link>
9+
<nz-link nzHref="#api" nzTitle="API">
10+
<nz-link nzHref="#nz-anchor" nzTitle="nz-anchor"></nz-link>
11+
<nz-link nzHref="#nz-link" nzTitle="nz-link"></nz-link>
12+
</nz-link>
13+
</nz-anchor>
14+
`
15+
})
16+
export class NzDemoAnchorOnChangeComponent {
17+
handleChange(link: string): void {
18+
console.log('Anchor:OnChange', link);
19+
}
20+
}

components/anchor/demo/on-click.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
order: 3
3+
title:
4+
zh-CN: 自定义 onClick 事件
5+
en-US: Customize the onClick event
6+
---
7+
8+
## zh-CN
9+
10+
点击锚点不记录历史。
11+
12+
## en-US
13+
14+
Clicking on an anchor does not record history.

components/anchor/demo/on-click.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'nz-demo-anchor-on-click',
5+
template: `
6+
<nz-anchor (nzClick)="handleClick($event)">
7+
<nz-link nzHref="#components-anchor-demo-basic" nzTitle="Basic demo"></nz-link>
8+
<nz-link nzHref="#components-anchor-demo-static" nzTitle="Static demo"></nz-link>
9+
<nz-link nzHref="#api" nzTitle="API">
10+
<nz-link nzHref="#nz-anchor" nzTitle="nz-anchor"></nz-link>
11+
<nz-link nzHref="#nz-link" nzTitle="nz-link"></nz-link>
12+
</nz-link>
13+
</nz-anchor>
14+
`
15+
})
16+
export class NzDemoAnchorOnClickComponent {
17+
handleClick(e: string): void {
18+
console.log(e);
19+
}
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
order: 5
3+
title:
4+
zh-CN: 设置锚点滚动偏移量
5+
en-US: Set Anchor scroll offset
6+
---
7+
8+
## zh-CN
9+
10+
锚点目标滚动到屏幕正中间。
11+
12+
## en-US
13+
14+
Anchor target scroll to screen center.

0 commit comments

Comments
 (0)