当前位置: 首页 > 工具软件 > ng-zorro-antd > 使用案例 >

前端知识之angular组件库之NG-ZORRO-ANTD结构窥探(三)pipe ,polify,service

周云
2023-12-01

ng-zorro-antd 结构窥探(三)

pipe

新增加了一个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('');
}

polyfill

主要是增加功能函数: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();

resize-observer

检测组件,页面的缩放

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);
    }
  }
}

参考

1.angular - simplejason 个人主页

2.Angular 练级之旅(6)-CDK的使用

3. angular material design

4.使用 Angular CDK 技术来创建一个消息推送服务(toast service)

 类似资料: