projects/rebirth-ng/src/lib/slider/slider.component.ts
AfterViewInit
OnInit
OnDestroy
ControlValueAccessor
changeDetection | ChangeDetectionStrategy.OnPush |
exportAs | slider |
providers |
{
: , : (() => ), : true
}
|
selector | re-slider |
styleUrls | slider.component.scss |
templateUrl | ./slider.component.html |
Properties |
|
Methods |
|
Inputs |
Outputs |
HostListeners |
constructor(changeDetectorRef: ChangeDetectorRef, rebirthNGConfig: RebirthNGConfig, documentRef: DocumentRef, windowRef: WindowRef)
|
|||||||||||||||
Parameters :
|
max
|
|
min
|
|
onChange
|
$event type: EventEmitter<number>
|
window:resize |
window:resize()
|
Private calcHandleOffset |
calcHandleOffset()
|
Returns :
void
|
Private calcValueWhenMove | ||||||
calcValueWhenMove(event: MouseEvent)
|
||||||
Parameters :
Returns :
void
|
Private changeValue | ||||
changeValue(newValue: )
|
||||
Parameters :
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
Public onOperateValue | ||||||
onOperateValue(value: number)
|
||||||
Parameters :
Returns :
void
|
Public onSliderClick | ||||
onSliderClick(event: )
|
||||
Parameters :
Returns :
void
|
Public operateValue | ||||||
operateValue(value: number)
|
||||||
Parameters :
Returns :
void
|
registerOnChange | ||||||
registerOnChange(fn: any)
|
||||||
Parameters :
Returns :
void
|
registerOnTouched | ||||||
registerOnTouched(fn: any)
|
||||||
Parameters :
Returns :
void
|
writeValue | ||||||
writeValue(value: number)
|
||||||
Parameters :
Returns :
void
|
Private complete$ |
complete$:
|
Default value : new Subject<void>()
|
dot |
dot:
|
Type : ElementRef
|
Decorators : ViewChild
|
handleOffset |
handleOffset:
|
Type : number
|
Default value : 0
|
Private offset |
offset:
|
Type : number
|
Private onTouched |
onTouched:
|
Default value : () => null
|
Private onValueChange |
onValueChange:
|
Default value : (_: any) => null
|
slider |
slider:
|
Type : ElementRef
|
Decorators : ViewChild
|
Private stepWidth |
stepWidth:
|
Type : number
|
value |
value:
|
Type : number
|
Default value : 0
|
import {
Component,
ChangeDetectorRef,
ChangeDetectionStrategy,
forwardRef,
AfterViewInit,
ViewChild,
ElementRef,
OnDestroy,
OnInit,
Input,
Output,
EventEmitter,
HostListener
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject, fromEvent } from 'rxjs';
import { switchMap, take, takeUntil } from 'rxjs/operators';
import { RebirthNGConfig } from '../rebirth-ng.config';
import { DocumentRef } from '../window-ref/document-ref.service';
import { WindowRef } from '../window-ref/window-ref.service';
@Component({
selector: 're-slider',
templateUrl: './slider.component.html',
styleUrls: ['./slider.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'slider',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SliderComponent),
multi: true
}
]
})
export class SliderComponent implements AfterViewInit, OnInit, OnDestroy, ControlValueAccessor {
@ViewChild('sliderDot') dot: ElementRef;
@ViewChild('slider') slider: ElementRef;
@Output() onChange: EventEmitter<number> = new EventEmitter<number>();
handleOffset = 0;
@Input() max;
@Input() min;
private offset: number;
private stepWidth: number;
value = 0;
private complete$ = new Subject<void>();
private onValueChange = (_: any) => null;
private onTouched = () => null;
constructor(private changeDetectorRef: ChangeDetectorRef,
private rebirthNGConfig: RebirthNGConfig,
private documentRef: DocumentRef,
private windowRef: WindowRef) {
this.max = rebirthNGConfig.slider.max;
this.min = rebirthNGConfig.slider.min;
}
ngOnInit() {
this.offset = this.max - this.min;
}
ngOnDestroy() {
this.complete$.complete();
}
ngAfterViewInit() {
this.stepWidth = this.windowRef.getOffsetWidth(this.slider) / this.offset;
const mousedown$ = fromEvent(this.dot.nativeElement, 'mousedown');
const mousemove$ = fromEvent(this.documentRef.document, 'mousemove');
const mouseup$ = fromEvent(this.documentRef.document, 'mouseup');
mousedown$
.pipe(
switchMap(() => {
this.onTouched();
return mousemove$.pipe(takeUntil(mouseup$));
}),
takeUntil(this.complete$)
)
.subscribe((event: MouseEvent) => {
event.preventDefault();
this.calcValueWhenMove(event);
this.changeDetectorRef.markForCheck();
});
mousedown$
.pipe(
switchMap(() => {
this.onTouched();
return mouseup$.pipe(take(1));
}),
takeUntil(this.complete$)
)
.subscribe((event: MouseEvent) => {
event.preventDefault();
this.calcValueWhenMove(event);
this.calcHandleOffset();
this.changeDetectorRef.markForCheck();
});
}
@HostListener('window:resize')
onResize() {
this.stepWidth = this.windowRef.getOffsetWidth(this.slider) / this.offset;
this.calcHandleOffset();
}
public onSliderClick(event) {
this.calcValueWhenMove(event);
}
public onOperateValue(value: number): void {
this.onTouched();
this.operateValue(value);
}
public operateValue(value: number): void {
this.changeValue(value);
this.calcHandleOffset();
}
private calcHandleOffset(): void {
this.handleOffset = this.value * this.stepWidth;
}
private calcValueWhenMove(event: MouseEvent): void {
const rect = this.windowRef.getBoundingClientRect(this.slider)// IE >= 9
const mouseRelativeSliderOffsetX = event.clientX - rect.left;
const fixedOffsetX = Math.max(Math.min(mouseRelativeSliderOffsetX, rect.width), 0);
this.handleOffset = fixedOffsetX;
this.changeValue(Math.round(fixedOffsetX / this.stepWidth));
}
private changeValue(newValue): void {
const fixedValue = Math.max(Math.min(newValue, this.max), 0);
if (fixedValue === this.value) {
return;
}
this.value = fixedValue;
const outSideValue = fixedValue + this.min;
this.onValueChange(outSideValue);
this.onChange.emit(outSideValue);
}
writeValue(value: number) {
const sideValue = value ? value - this.min : this.min;
this.operateValue(sideValue);
this.changeDetectorRef.markForCheck();
}
registerOnChange(fn: any) {
this.onValueChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
}
<div class="slider-body">
<div class="slider-container">
<div #slider class="slider">
<div class="base-line" (click)="onSliderClick($event)">
<div class="active-line" [style.width.px]="handleOffset"></div>
</div>
</div>
<div #sliderDot [style.left.px]="handleOffset" class="handle" [attr.title]="value"></div>
</div>
<div class="slider-operator-container">
<button class="btn reduce" (click)="onOperateValue(value - 1)">-</button>
<button class="btn plus" (click)="onOperateValue(value + 1)">+</button>
</div>
</div>