diff --git a/components/slider/demo/reverse.md b/components/slider/demo/reverse.md new file mode 100644 index 00000000000..ed922d9013a --- /dev/null +++ b/components/slider/demo/reverse.md @@ -0,0 +1,15 @@ +--- +order: 8 +title: + zh-CN: 反向 + en-US: Reverse +--- + +## zh-CN + +设置 `nzReverse` 可以将滑动条置反。 + +## en-US + +Using `nzReverse` to render slider reversely. + diff --git a/components/slider/demo/reverse.ts b/components/slider/demo/reverse.ts new file mode 100644 index 00000000000..80d7105f29e --- /dev/null +++ b/components/slider/demo/reverse.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'nz-demo-slider-reverse', + template: ` +
+ + + Reversed: +
+ `, + styles: [ + ` + h4 { + margin: 0 0 16px; + } + + .ant-slider-with-marks { + margin-bottom: 44px; + } + ` + ] +}) +export class NzDemoSliderReverseComponent { + reverse = true; +} diff --git a/components/slider/doc/index.en-US.md b/components/slider/doc/index.en-US.md index 5b291942cff..3ad0095dff4 100644 --- a/components/slider/doc/index.en-US.md +++ b/components/slider/doc/index.en-US.md @@ -31,6 +31,7 @@ import { NzSliderModule } from 'ng-zorro-antd/slider'; | `[nzTipFormatter]` | Slider will pass its value to `tipFormatter`, and display its value in Tooltip, and hide Tooltip when return value is null. | `(value: number) => string` | - | | `[ngModel]` | The value of slider. When `range` is `false`, use `number`, otherwise, use `[number, number]` | `number \| number[]` | - | | `[nzVertical]` | If true, the slider will be vertical. | `boolean` | `false` | +| `[nzReverse]` | Reverse the component | `boolean` | `false` | | `[nzTooltipVisible]` | When set to `always` tooltips are always displayed. When set to `never` they are never displayed | `'default' \| 'always' \| 'never'` | `default` | | `[nzTooltipPlacement]` | Set the default placement of Tooltip | `string` | | | `(nzOnAfterChange)` | Fire when `onmouseup` is fired. | `EventEmitter` | - | diff --git a/components/slider/doc/index.zh-CN.md b/components/slider/doc/index.zh-CN.md index 208178863d0..16b4a0fd463 100644 --- a/components/slider/doc/index.zh-CN.md +++ b/components/slider/doc/index.zh-CN.md @@ -32,6 +32,7 @@ import { NzSliderModule } from 'ng-zorro-antd/slider'; | `[nzTipFormatter]` | Slider 会把当前值传给 `nzTipFormatter`,并在 Tooltip 中显示 `nzTipFormatter` 的返回值,若为 null,则隐藏 Tooltip。 | `(value: number) => string` | - | | `[ngModel]` | 设置当前取值。当 `range` 为 `false` 时,使用 `number`,否则用 `[number, number]` | `number \| number[]` | - | | `[nzVertical]` | 值为 `true` 时,Slider 为垂直方向 | `boolean` | `false` | +| `[nzReverse]` | 反向坐标轴 | `boolean` | `false` | | `[nzTooltipVisible]` | 值为 `always` 时总是显示,值为 `never` 时在任何情况下都不显示 | `'default' \| 'always' \| 'never'` | `default` | | `[nzTooltipPlacement]` | 设置 Tooltip 的默认位置。 | `string` | | | `(nzOnAfterChange)` | 与 `onmouseup` 触发时机一致,把当前值作为参数传入。 | `EventEmitter` | - | diff --git a/components/slider/handle.component.ts b/components/slider/handle.component.ts index 41aab659101..3e9b7d4715c 100644 --- a/components/slider/handle.component.ts +++ b/components/slider/handle.component.ts @@ -54,6 +54,7 @@ export class NzSliderHandleComponent implements OnChanges { @ViewChild(NzTooltipDirective, { static: false }) tooltip: NzTooltipDirective; @Input() vertical: string; + @Input() reverse: string; @Input() offset: number; @Input() value: number; @Input() tooltipVisible: NzSliderShowTooltip = 'default'; @@ -67,9 +68,9 @@ export class NzSliderHandleComponent implements OnChanges { constructor(private sliderService: NzSliderService, private cdr: ChangeDetectorRef) {} ngOnChanges(changes: SimpleChanges): void { - const { offset, value, active, tooltipVisible } = changes; + const { offset, value, active, tooltipVisible, reverse } = changes; - if (offset) { + if (offset || reverse) { this.updateStyle(); } @@ -133,10 +134,23 @@ export class NzSliderHandleComponent implements OnChanges { } private updateStyle(): void { - this.style = { - [this.vertical ? 'bottom' : 'left']: `${this.offset}%`, - transform: this.vertical ? 'translateY(50%)' : 'translateX(-50%)' - }; + const vertical = this.vertical; + const reverse = this.reverse; + const offset = this.offset; + + const positionStyle = vertical + ? { + [reverse ? 'top' : 'bottom']: `${offset}%`, + [reverse ? 'bottom' : 'top']: 'auto', + transform: reverse ? null : `translateY(+50%)` + } + : { + [reverse ? 'right' : 'left']: `${offset}%`, + [reverse ? 'left' : 'right']: 'auto', + transform: `translateX(${reverse ? '+' : '-'}50%)` + }; + + this.style = positionStyle; this.cdr.markForCheck(); } } diff --git a/components/slider/slider.component.ts b/components/slider/slider.component.ts index dc769ca03b1..a4a48562d3e 100644 --- a/components/slider/slider.component.ts +++ b/components/slider/slider.component.ts @@ -73,7 +73,13 @@ import { NzExtendedMark, NzMarks, NzSliderHandler, NzSliderShowTooltip, NzSlider [class.ant-slider-with-marks]="marksArray" >
- + { let sliderInstance: NzSliderComponent; let overlayContainerElement: HTMLElement; - // tslint:disable-next-line:no-any - function getReferenceFromFixture(fixture: ComponentFixture): void { + function getReferenceFromFixture(fixture: ComponentFixture): void { sliderDebugElement = fixture.debugElement.query(By.directive(NzSliderComponent)); sliderInstance = sliderDebugElement.componentInstance; sliderNativeElement = sliderInstance.slider.nativeElement; @@ -491,6 +491,49 @@ describe('nz-slider', () => { }); }); + describe('reverse', () => { + let testBed: ComponentBed; + let fixture: ComponentFixture; + let sliderDebugElements: DebugElement[]; + + beforeEach(() => { + testBed = createComponentBed(ReverseSliderComponent, { + imports: [NzSliderModule, FormsModule, ReactiveFormsModule, NoopAnimationsModule] + }); + fixture = testBed.fixture; + fixture.detectChanges(); + + sliderDebugElements = fixture.debugElement.queryAll(By.directive(NzSliderComponent)); + }); + + it('should reverse work', () => { + const trackElement = (sliderDebugElements[0].nativeElement as HTMLElement).querySelector('.ant-slider-track') as HTMLElement; + expect(trackElement.style.right).toBe('0%'); + + const rangeTrackElement = (sliderDebugElements[1].nativeElement as HTMLElement).querySelector('.ant-slider-track') as HTMLElement; + expect(trackElement.style.right).toBe('0%'); + expect(rangeTrackElement.style.width).toBe('100%'); + + const verticalTrackElement = (sliderDebugElements[2].nativeElement as HTMLElement).querySelector('.ant-slider-track') as HTMLElement; + expect(verticalTrackElement.style.top).toBe('0%'); + }); + + it('should respond to keyboard event reversely', () => { + getReferenceFromFixture(fixture); + + dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW); + dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW); + dispatchKeyboardEvent(sliderNativeElement, 'keydown', DOWN_ARROW); + dispatchKeyboardEvent(sliderNativeElement, 'keydown', UP_ARROW); + dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW); + + fixture.detectChanges(); + + const trackElement = (sliderDebugElements[0].nativeElement as HTMLElement).querySelector('.ant-slider-track') as HTMLElement; + expect(trackElement.style.width).toBe('1%'); + }); + }); + describe('mixed usage', () => { let testBed: ComponentBed; let fixture: ComponentFixture; @@ -743,18 +786,14 @@ const styles = ` `; @Component({ - template: ` - - `, + template: ` `, styles: [styles] }) class NzTestSliderComponent { disabled = false; } @Component({ - template: ` - - `, + template: ` `, styles: [styles] }) class SliderWithMinAndMaxComponent { @@ -763,17 +802,13 @@ class SliderWithMinAndMaxComponent { } @Component({ - template: ` - - `, + template: ` `, styles: [styles] }) class SliderWithValueComponent {} @Component({ - template: ` - - `, + template: ` `, styles: [styles] }) class SliderWithStepComponent { @@ -781,29 +816,32 @@ class SliderWithStepComponent { } @Component({ - template: ` - - `, + template: ` `, styles: [styles] }) class SliderWithValueSmallerThanMinComponent {} @Component({ - template: ` - - `, + template: ` `, styles: [styles] }) class SliderWithValueGreaterThanMaxComponent {} @Component({ - template: ` - - `, + template: ` `, styles: [styles] }) class VerticalSliderComponent {} +@Component({ + template: ` + + + + ` +}) +class ReverseSliderComponent {} + @Component({ template: ` - ` + template: ` ` }) class SliderShowTooltipComponent { show: NzSliderShowTooltip = 'default'; @@ -860,9 +896,7 @@ class SliderShowTooltipComponent { } @Component({ - template: ` - - ` + template: ` ` }) class NzTestSliderKeyboardComponent { range = false; diff --git a/components/slider/track.component.ts b/components/slider/track.component.ts index 0403d08abac..30ed316468a 100644 --- a/components/slider/track.component.ts +++ b/components/slider/track.component.ts @@ -6,9 +6,8 @@ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ -import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnChanges, ViewEncapsulation } from '@angular/core'; import { BooleanInput, NumberInput } from 'ng-zorro-antd/core/types'; - import { InputBoolean, InputNumber } from 'ng-zorro-antd/core/util'; export interface NzSliderTrackStyle { @@ -34,28 +33,34 @@ export class NzSliderTrackComponent implements OnChanges { static ngAcceptInputType_included: BooleanInput; @Input() @InputNumber() offset: number; + @Input() @InputBoolean() reverse: boolean = false; @Input() @InputNumber() length: number; @Input() @InputBoolean() vertical = false; @Input() @InputBoolean() included = false; style: NzSliderTrackStyle = {}; - ngOnChanges(changes: SimpleChanges): void { - if (changes.included) { - this.style.visibility = this.included ? 'visible' : 'hidden'; - } - if (changes.vertical || changes.offset || changes.length) { - if (this.vertical) { - this.style.bottom = `${this.offset}%`; - this.style.height = `${this.length}%`; - this.style.left = null; - this.style.width = null; - } else { - this.style.left = `${this.offset}%`; - this.style.width = `${this.length}%`; - this.style.bottom = null; - this.style.height = null; - } - } + ngOnChanges(): void { + const vertical = this.vertical; + const reverse = this.reverse; + const visibility = this.included ? 'visible' : 'hidden'; + const offset = this.offset; + const length = this.length; + + const positonStyle: NzSliderTrackStyle = vertical + ? { + [reverse ? 'top' : 'bottom']: `${offset}%`, + [reverse ? 'bottom' : 'top']: 'auto', + height: `${length}%`, + visibility + } + : { + [reverse ? 'right' : 'left']: `${offset}%`, + [reverse ? 'left' : 'right']: 'auto', + width: `${length}%`, + visibility + }; + + this.style = positonStyle; } }