新增加了一个time-range的管道
import { Pipe, PipeTransform } from '@angular/core';
import { timeUnits } from 'ng-zorro-antd/core/time';
import { padStart } from 'ng-zorro-antd/core/util';
@Pipe({
name: 'nzTimeRange',
pure: true
})
export class NzTimeRangePipe implements PipeTransform {
transform(value: string | number, format: string = 'HH:mm:ss'): string {
let duration = Number(value || 0);
return timeUnits.reduce((current, [name, unit]) => {
if (current.indexOf(name) !== -1) {
const v = Math.floor(duration / unit);
duration -= v * unit;
return current.replace(new RegExp(`${name}+`, 'g'), (match: string) => {
return padStart(v.toString(), match.length, '0');
});
}
return current;
}, format);
}
}
timeUnits.ts
export const timeUnits: Array<[string, number]> = [
['Y', 1000 * 60 * 60 * 24 * 365], // years
['M', 1000 * 60 * 60 * 24 * 30], // months
['D', 1000 * 60 * 60 * 24], // days
['H', 1000 * 60 * 60], // hours
['m', 1000 * 60], // minutes
['s', 1000], // seconds
['S', 1] // million seconds
];
string.ts
export function padStart(toPad: string, length: number, element: string): string {
if (toPad.length > length) {
return toPad;
}
const joined = `${getRepeatedElement(length, element)}${toPad}`;
return joined.slice(joined.length - length, joined.length);
}
export function padEnd(toPad: string, length: number, element: string): string {
const joined = `${toPad}${getRepeatedElement(length, element)}`;
return joined.slice(0, length);
}
export function getRepeatedElement(length: number, element: string): string {
return Array(length).fill(element).join('');
}
主要是增加功能函数:requestAnimationFramePolyfill
// tslint:disable: typedef no-invalid-this
const availablePrefixes = ['moz', 'ms', 'webkit'];
function requestAnimationFramePolyfill(): typeof requestAnimationFrame {
let lastTime = 0;
return function (callback: FrameRequestCallback): number {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime)); // 60FPS 1000/60 ≈16
const id = setTimeout(() => {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
// support or not
function getRequestAnimationFrame(): typeof requestAnimationFrame {
if (typeof window === 'undefined') {
return () => 0;
}
if (window.requestAnimationFrame) { // exist requestAnimationFrame
// https://github.com/vuejs/vue/issues/4465
return window.requestAnimationFrame.bind(window);
}
const prefix = availablePrefixes.filter(key => `${key}RequestAnimationFrame` in window)[0];
return prefix ? (window as NzSafeAny)[`${prefix}RequestAnimationFrame`] : requestAnimationFramePolyfill();
}
export function cancelRequestAnimationFrame(id: number): NzSafeAny {
if (typeof window === 'undefined') {
return null;
}
if (window.cancelAnimationFrame) {
return window.cancelAnimationFrame(id);
}
const prefix = availablePrefixes.filter(
key => `${key}CancelAnimationFrame` in window || `${key}CancelRequestAnimationFrame` in window
)[0];
return prefix
? ((window as NzSafeAny)[`${prefix}CancelAnimationFrame`] || (window as NzSafeAny)[`${prefix}CancelRequestAnimationFrame`])
// @ts-ignore
.call(this, id)
: clearTimeout(id);
}
export const reqAnimFrame = getRequestAnimationFrame();
检测组件,页面的缩放
import { coerceElement } from '@angular/cdk/coercion';
import { ElementRef, Injectable, OnDestroy } from '@angular/core';
import ResizeObserver from 'resize-observer-polyfill';
import { Observable, Observer, Subject } from 'rxjs';
/**
* Factory that creates a new ResizeObserver and allows us to stub it out in unit tests.
*/
@Injectable({ providedIn: 'root' })
export class NzResizeObserverFactory {
//创建resize-observer
create(callback: ResizeObserverCallback): ResizeObserver | null {
return typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(callback);
}
}
/** An injectable service that allows watching elements for changes to their content. */
@Injectable({ providedIn: 'root' })
export class NzResizeObserver implements OnDestroy {
/** Keeps track of the existing ResizeObservers so they can be reused. */
private observedElements = new Map<
Element,
{
observer: ResizeObserver | null;
stream: Subject<ResizeObserverEntry[]>;
count: number;
}
>();
constructor(private nzResizeObserverFactory: NzResizeObserverFactory) {}
ngOnDestroy(): void {
this.observedElements.forEach((_, element) => this.cleanupObserver(element));
}
observe(elementOrRef: Element | ElementRef<Element>): Observable<ResizeObserverEntry[]> {
// from angular/cdk->coercion
/**
* Coerces an ElementRef or an Element into an element.
* Useful for APIs that can accept either a ref or the native element itself.
*/
const element = coerceElement(elementOrRef);
return new Observable((observer: Observer<ResizeObserverEntry[]>) => {
const stream = this.observeElement(element);
const subscription = stream.subscribe(observer);
return () => {
subscription.unsubscribe();
this.unobserveElement(element);
};
});
}
/**
* Observes the given element by using the existing ResizeObserver if available, or creating a
* new one if not.
*/
private observeElement(element: Element): Subject<ResizeObserverEntry[]> {
if (!this.observedElements.has(element)) {
const stream = new Subject<ResizeObserverEntry[]>();
const observer = this.nzResizeObserverFactory.create(mutations => stream.next(mutations));
if (observer) {
observer.observe(element);
}
this.observedElements.set(element, { observer, stream, count: 1 });
} else {
this.observedElements.get(element)!.count++;
}
return this.observedElements.get(element)!.stream;
}
/**
* Un-observes the given element and cleans up the underlying ResizeObserver if nobody else is
* observing this element.
*/
private unobserveElement(element: Element): void {
if (this.observedElements.has(element)) {
this.observedElements.get(element)!.count--;
if (!this.observedElements.get(element)!.count) {
this.cleanupObserver(element);
}
}
}
/** Clean up the underlying ResizeObserver for the specified element. */
private cleanupObserver(element: Element): void {
if (this.observedElements.has(element)) {
const { observer, stream } = this.observedElements.get(element)!;
if (observer) {
observer.disconnect();
}
stream.complete();
this.observedElements.delete(element);
}
}
}