Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(module:anchor): sync new properties #7494

Merged
merged 1 commit into from Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion components/anchor/anchor-link.component.ts
Expand Up @@ -27,7 +27,14 @@ import { NzAnchorComponent } from './anchor.component';
exportAs: 'nzLink',
preserveWhitespaces: false,
template: `
<a #linkTitle (click)="goToClick($event)" href="{{ nzHref }}" class="ant-anchor-link-title" title="{{ titleStr }}">
<a
#linkTitle
class="ant-anchor-link-title"
[href]="nzHref"
[title]="titleStr"
[target]="nzTarget"
(click)="goToClick($event)"
>
<span *ngIf="titleStr; else titleTpl || nzTemplate">{{ titleStr }}</span>
</a>
<ng-content></ng-content>
Expand All @@ -37,6 +44,7 @@ import { NzAnchorComponent } from './anchor.component';
})
export class NzAnchorLinkComponent implements OnInit, OnDestroy {
@Input() nzHref = '#';
@Input() nzTarget?: string;

titleStr: string | null = '';
titleTpl?: TemplateRef<NzSafeAny>;
Expand Down
37 changes: 31 additions & 6 deletions components/anchor/anchor.component.ts
Expand Up @@ -92,15 +92,23 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
@WithConfig<number>()
nzOffsetTop?: number = undefined;

@Input()
@InputNumber(undefined)
@WithConfig<number>()
nzTargetOffset?: number = undefined;

@Input() nzContainer?: string | HTMLElement;
@Input() nzCurrentAnchor?: string;

@Output() readonly nzClick = new EventEmitter<string>();
@Output() readonly nzChange = new EventEmitter<string>();
@Output() readonly nzScroll = new EventEmitter<NzAnchorLinkComponent>();

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

container?: HTMLElement | Window;
activeLink?: string;

private links: NzAnchorLinkComponent[] = [];
private animating = false;
Expand Down Expand Up @@ -160,7 +168,8 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
}

const sections: Section[] = [];
const scope = (this.nzOffsetTop || 0) + this.nzBounds;
const offsetTop = this.nzTargetOffset ? this.nzTargetOffset : this.nzOffsetTop || 0;
const scope = offsetTop + this.nzBounds;
this.links.forEach(comp => {
const sharpLinkMatch = sharpMatcherRegx.exec(comp.nzHref.toString());
if (!sharpLinkMatch) {
Expand Down Expand Up @@ -195,11 +204,23 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
});
}

private setActive(comp?: NzAnchorLinkComponent): void {
const originalActiveLink = this.activeLink;
const targetComp = (this.nzCurrentAnchor && this.links.find(n => n.nzHref === this.nzCurrentAnchor)) || comp;
if (!targetComp) return;

targetComp.setActive();
const linkNode = targetComp.getLinkTitleElement();
this.ink.nativeElement.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
this.activeLink = (comp || targetComp).nzHref;
if (originalActiveLink !== this.activeLink) {
this.nzChange.emit(this.activeLink);
}
}

private handleActive(comp: NzAnchorLinkComponent): void {
this.clearActive();
comp.setActive();
const linkNode = comp.getLinkTitleElement();
this.ink.nativeElement.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
this.setActive(comp);
this.visible = true;
this.setVisible();
this.nzScroll.emit(comp);
Expand All @@ -226,7 +247,8 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
this.animating = true;
const containerScrollTop = this.scrollSrv.getScroll(this.getContainer());
const elOffsetTop = getOffsetTop(el, this.getContainer());
const targetScrollTop = containerScrollTop + elOffsetTop - (this.nzOffsetTop || 0);
let targetScrollTop = containerScrollTop + elOffsetTop;
targetScrollTop -= this.nzTargetOffset !== undefined ? this.nzTargetOffset : this.nzOffsetTop || 0;
this.scrollSrv.scrollTo(this.getContainer(), targetScrollTop, {
callback: () => {
this.animating = false;
Expand All @@ -237,7 +259,7 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
}

ngOnChanges(changes: SimpleChanges): void {
const { nzOffsetTop, nzContainer } = changes;
const { nzOffsetTop, nzContainer, nzCurrentAnchor } = changes;
if (nzOffsetTop) {
this.wrapperStyle = {
'max-height': `calc(100vh - ${this.nzOffsetTop}px)`
Expand All @@ -248,5 +270,8 @@ export class NzAnchorComponent implements OnDestroy, AfterViewInit, OnChanges {
this.container = typeof container === 'string' ? this.doc.querySelector(container) : container;
this.registerScrollEvent();
}
if (nzCurrentAnchor) {
this.setActive();
}
}
}
43 changes: 43 additions & 0 deletions components/anchor/anchor.spec.ts
Expand Up @@ -26,6 +26,7 @@ describe('anchor', () => {
fixture.detectChanges();
page = new PageObject();
spyOn(context, '_scroll');
spyOn(context, '_change');
srv = TestBed.inject(NzScrollService);
});
afterEach(() => context.comp.ngOnDestroy());
Expand Down Expand Up @@ -131,6 +132,18 @@ describe('anchor', () => {
});
});

describe('[nzCurrentAnchor]', () => {
it('customize the anchor highlight', () => {
context.nzCurrentAnchor = '#basic';
fixture.detectChanges();
const linkList = dl.queryAll(By.css('.ant-anchor-link'));
expect(linkList.length).toBeGreaterThan(0);
const activeLink = linkList.find(n => (n.nativeElement as HTMLDivElement).getAttribute('nzhref') === '#basic')!;
expect(activeLink).toBeTruthy();
expect((activeLink.nativeElement as HTMLDivElement).classList).toContain('ant-anchor-link-active');
});
});

describe('[nzShowInkInFixed]', () => {
beforeEach(() => {
context.nzAffix = false;
Expand Down Expand Up @@ -169,6 +182,30 @@ describe('anchor', () => {
});
});

describe('(nzChange)', () => {
it('should emit nzChange when click a link', fakeAsync(() => {
spyOn(srv, 'scrollTo').and.callFake((_containerEl, _targetTopValue = 0, options = {}) => {
if (options.callback) {
options.callback();
}
});
expect(context._change).not.toHaveBeenCalled();
page.to('#basic-target');
expect(context._change).toHaveBeenCalled();
}));
it('should emit nzChange when scrolling to the anchor', (done: () => void) => {
spyOn(context, '_change');
expect(context._change).not.toHaveBeenCalled();
page.scrollTo();
setTimeout(() => {
const inkNode = page.getEl('.ant-anchor-ink-ball');
expect(+inkNode.style.top!.replace('px', '')).toBeGreaterThan(0);
expect(context._change).toHaveBeenCalled();
done();
}, throttleTime);
});
});

it('(nzClick)', () => {
spyOn(context, '_click');
expect(context._click).not.toHaveBeenCalled();
Expand Down Expand Up @@ -233,9 +270,12 @@ describe('anchor', () => {
[nzBounds]="nzBounds"
[nzShowInkInFixed]="nzShowInkInFixed"
[nzOffsetTop]="nzOffsetTop"
[nzTargetOffset]="nzTargetOffset"
[nzContainer]="nzContainer"
[nzCurrentAnchor]="nzCurrentAnchor"
(nzClick)="_click($event)"
(nzScroll)="_scroll($event)"
(nzChange)="_change($event)"
>
<nz-link nzHref="#何时使用" nzTitle="何时使用"></nz-link>
<nz-link nzHref="#basic" nzTitle="Basic demo"></nz-link>
Expand Down Expand Up @@ -288,8 +328,11 @@ export class TestComponent {
nzAffix = true;
nzBounds = 5;
nzOffsetTop = 0;
nzTargetOffset?: number;
nzShowInkInFixed = false;
nzContainer: any = null;
nzCurrentAnchor?: string;
_click() {}
_change() {}
_scroll() {}
}
14 changes: 14 additions & 0 deletions components/anchor/demo/customize-highlight.md
@@ -0,0 +1,14 @@
---
order: 4
title:
zh-CN: 自定义锚点高亮
en-US: Customize the anchor highlight
---

## zh-CN

自定义锚点高亮。

## en-US

Customize the anchor highlight.
16 changes: 16 additions & 0 deletions components/anchor/demo/customize-highlight.ts
@@ -0,0 +1,16 @@
import { Component } from '@angular/core';

@Component({
selector: 'nz-demo-anchor-customize-highlight',
template: `
<nz-anchor nzCurrentAnchor="#components-anchor-demo-static">
<nz-link nzHref="#components-anchor-demo-basic" nzTitle="Basic demo"></nz-link>
<nz-link nzHref="#components-anchor-demo-static" nzTitle="Static demo"></nz-link>
<nz-link nzHref="#api" nzTitle="API">
<nz-link nzHref="#nz-anchor" nzTitle="nz-anchor"></nz-link>
<nz-link nzHref="#nz-link" nzTitle="nz-link"></nz-link>
</nz-link>
</nz-anchor>
`
})
export class NzDemoAnchorCustomizeHighlightComponent {}
14 changes: 14 additions & 0 deletions components/anchor/demo/on-change.md
@@ -0,0 +1,14 @@
---
order: 6
title:
zh-CN: 监听锚点链接改变
en-US: Listening for anchor link change
---

## zh-CN

监听锚点链接改变

## en-US

Listening for anchor link change.
20 changes: 20 additions & 0 deletions components/anchor/demo/on-change.ts
@@ -0,0 +1,20 @@
import { Component } from '@angular/core';

@Component({
selector: 'nz-demo-anchor-on-change',
template: `
<nz-anchor (nzChange)="handleChange($event)">
<nz-link nzHref="#components-anchor-demo-basic" nzTitle="Basic demo"></nz-link>
<nz-link nzHref="#components-anchor-demo-static" nzTitle="Static demo"></nz-link>
<nz-link nzHref="#api" nzTitle="API">
<nz-link nzHref="#nz-anchor" nzTitle="nz-anchor"></nz-link>
<nz-link nzHref="#nz-link" nzTitle="nz-link"></nz-link>
</nz-link>
</nz-anchor>
`
})
export class NzDemoAnchorOnChangeComponent {
handleChange(link: string): void {
console.log('Anchor:OnChange', link);
}
}
14 changes: 14 additions & 0 deletions components/anchor/demo/on-click.md
@@ -0,0 +1,14 @@
---
order: 3
title:
zh-CN: 自定义 onClick 事件
en-US: Customize the onClick event
---

## zh-CN

点击锚点不记录历史。

## en-US

Clicking on an anchor does not record history.
20 changes: 20 additions & 0 deletions components/anchor/demo/on-click.ts
@@ -0,0 +1,20 @@
import { Component } from '@angular/core';

@Component({
selector: 'nz-demo-anchor-on-click',
template: `
<nz-anchor (nzClick)="handleClick($event)">
<nz-link nzHref="#components-anchor-demo-basic" nzTitle="Basic demo"></nz-link>
<nz-link nzHref="#components-anchor-demo-static" nzTitle="Static demo"></nz-link>
<nz-link nzHref="#api" nzTitle="API">
<nz-link nzHref="#nz-anchor" nzTitle="nz-anchor"></nz-link>
<nz-link nzHref="#nz-link" nzTitle="nz-link"></nz-link>
</nz-link>
</nz-anchor>
`
})
export class NzDemoAnchorOnClickComponent {
handleClick(e: string): void {
console.log(e);
}
}
14 changes: 14 additions & 0 deletions components/anchor/demo/target-offset.md
@@ -0,0 +1,14 @@
---
order: 5
title:
zh-CN: 设置锚点滚动偏移量
en-US: Set Anchor scroll offset
---

## zh-CN

锚点目标滚动到屏幕正中间。

## en-US

Anchor target scroll to screen center.
22 changes: 22 additions & 0 deletions components/anchor/demo/target-offset.ts
@@ -0,0 +1,22 @@
import { Component, OnInit } from '@angular/core';

@Component({
selector: 'nz-demo-anchor-target-offset',
template: `
<nz-anchor [nzTargetOffset]="targetOffset">
<nz-link nzHref="#components-anchor-demo-basic" nzTitle="Basic demo"></nz-link>
<nz-link nzHref="#components-anchor-demo-static" nzTitle="Static demo"></nz-link>
<nz-link nzHref="#api" nzTitle="API">
<nz-link nzHref="#nz-anchor" nzTitle="nz-anchor"></nz-link>
<nz-link nzHref="#nz-link" nzTitle="nz-link"></nz-link>
</nz-link>
</nz-anchor>
`
})
export class NzDemoAnchorTargetOffsetComponent implements OnInit {
targetOffset?: number;

ngOnInit(): void {
this.targetOffset = window.innerHeight / 2;
}
}
4 changes: 4 additions & 0 deletions components/anchor/doc/index.en-US.md
Expand Up @@ -25,13 +25,17 @@ import { NzAnchorModule } from 'ng-zorro-antd/anchor';
| `[nzBounds]` | Bounding distance of anchor area, unit: px | `number` | `5` | ✅ |
| `[nzOffsetTop]` | Pixels to offset from top when calculating position of scroll | `number` | `0` | ✅ |
| `[nzShowInkInFixed]` | Whether show ink-balls in Fixed mode | `boolean` | `false` | ✅ |
| `[nzTargetOffset]` | Anchor scroll offset, default as `offsetTop`, [example](#components-anchor-demo-targetOffset) | number | - | |
| `[nzContainer]` | Scrolling container | `string \| HTMLElement` | `window` |
| `[nzCurrentAnchor]` | Customize the anchor highlight | string | - | |
| `(nzClick)` | Click of Anchor item | `EventEmitter<string>` | - |
| `(nzChange)` | Listening for anchor link change | `EventEmitter<string>` | - | |
| `(nzScroll)` | The scroll function that is triggered when scrolling to an anchor. | `EventEmitter<NzAnchorLinkComponent>` | - |

### nz-link

| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| `[nzHref]` | target of hyperlink | `string` | - |
| `[nzTarget]` | Specifies where to display the linked URL | string | - | |
| `[nzTitle]` | content of hyperlink | `string \| TemplateRef<void>` | - |
4 changes: 4 additions & 0 deletions components/anchor/doc/index.zh-CN.md
Expand Up @@ -27,13 +27,17 @@ import { NzAnchorModule } from 'ng-zorro-antd/anchor';
| `[nzBounds]` | 锚点区域边界,单位:px | `number` | `5` | ✅ |
| `[nzOffsetTop]` | 距离窗口顶部达到指定偏移量后触发 | `number` | - | ✅ |
| `[nzShowInkInFixed]` | 固定模式是否显示小圆点 | `boolean` | `false` | ✅ |
| `[nzTargetOffset]` | 锚点滚动偏移量,默认与 offsetTop 相同,[例子](#components-anchor-demo-targetOffset) | number | - | |
| `[nzContainer]` | 指定滚动的容器 | `string \| HTMLElement` | `window` |
| `[nzCurrentAnchor]` | 自定义高亮的锚点 | string | - | |
| `(nzClick)` | 点击项触发 | `EventEmitter<string>` | - |
| `(nzChange)` | 监听锚点链接改变 | `EventEmitter<string>` | - | |
| `(nzScroll)` | 滚动至某锚点时触发 | `EventEmitter<NzAnchorLinkComponent>` | - |

### nz-link

| 成员 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| `[nzHref]` | 锚点链接 | `string` | - |
| `[nzTarget]` | 该属性指定在何处显示链接的资源。 | string | - | |
| `[nzTitle]` | 文字内容 | `string \| TemplateRef<void>` | - |