angular drectives: once-click/once-enter/auto-focus/detect-scroll

257 阅读1分钟

once-click

import { Directive, Input, OnDestroy, OnInit, HostListener, Output, EventEmitter, Renderer2, ElementRef } from '@angular/core';

import { throttleTime } from 'rxjs/operators';

import { Subject, Subscription } from 'rxjs';

\


\


@Directive({

  // tslint:disable-next-line: directive-selector

  selector: '[click.once]'

})

export class OnceClickDirective implements OnInit, OnDestroy {

  // tslint:disable-next-line:no-output-rename

  @Output('click.once') clickCall: EventEmitter<MouseEvent> = new EventEmitter();

  @Input() duration = 1000; // 必须是数字,传入时要用绑定语法

  private $sub = new Subject<any>();

  private subscription: Subscription;

  constructor(

    private renderer: Renderer2, // 导入Renderer

    private element: ElementRef

  ) { }

  ngOnInit() {

    this.subscription = this.$sub.pipe(

      throttleTime(this.duration)

    ).subscribe((e: MouseEvent) => {

      this.clickCall.emit(e);

    });

  }

  @HostListener('click', ['$event'])        // 监听宿主点击事件

  clickEvent(event: MouseEvent) {

    event.preventDefault();   // 阻止浏览器的默认行为

    event.stopPropagation();   // 阻止事件冒泡

    this.$sub.next(event);

  }

  ngOnDestroy() {

    this.subscription.unsubscribe();

  }

}

once-enter


  Directive,

  Input,

  OnDestroy,

  OnInit,

  HostListener,

  Output,

  EventEmitter,

  Renderer2,

  ElementRef

} from '@angular/core';

import { debounceTime, throttleTime } from 'rxjs/operators';

import { Subject, Subscription } from 'rxjs';

\


\


@Directive({

  selector: '[enter.once]'

})

export class OnceEnterDirective implements OnInit, OnDestroy {

  @Output('enter.once') enterCall: EventEmitter<MouseEvent> = new EventEmitter();

  @Input() duration = 1000; // 必须是数字,传入时要用绑定语法

  private $sub = new Subject<any>();

  private subscription: Subscription;

  constructor(

    private renderer: Renderer2, // 导入Renderer

    private element: ElementRef

  ) {}

  ngOnInit() {

    this.subscription = this.$sub

      .pipe(debounceTime(300), throttleTime(this.duration))

      .subscribe((e: MouseEvent) => {

        this.enterCall.emit(e);

      });

  }

\


\


  @HostListener('keyup.Enter', ['$event'])

  enterEvent(event: MouseEvent) {

    event.preventDefault(); // 通常是不需要冒泡的

    event.stopPropagation();

    this.$sub.next(event);

  }

  ngOnDestroy() {

    this.subscription.unsubscribe();

  }

}

auto-focus


@Directive({
  selector: '[appAutoFocus]'
})
export class AutoFocusDirective implements AfterContentInit {
  constructor(private el: ElementRef) {}

  ngAfterContentInit(): void {
    setTimeout(() => {
      this.el.nativeElement.focus();
    }, 500);
  }
}

detect-scroll

import { Directive, HostListener, Output, EventEmitter, Input } from '@angular/core';

export interface ScrollEvent {
  isReachingBottom: boolean;
  isReachingTop: boolean;
  originalEvent: Event;
  isWindowEvent: boolean;
}

declare const window: Window;

@Directive({
  selector: '[detectScroll]'
})
export class DetectScrollDirective {
  @Output() public onScroll = new EventEmitter<ScrollEvent>();
  @Input() public bottomOffset = 10;
  @Input() public topOffset = 10;

  constructor() {}

  // handle host scroll
  @HostListener('scroll', ['$event']) scrolled($event: Event) {
    this.elementScrollEvent($event);
  }

  // handle window scroll
  @HostListener('window:scroll', ['$event']) windowScrolled($event: Event) {
    this.windowScrollEvent($event);
  }

  protected windowScrollEvent($event: Event) {
    const target = <Document>$event.target;
    const scrollTop =
      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
    const isReachingTop = scrollTop < this.topOffset;
    const isReachingBottom =
      target.body.offsetHeight - (window.innerHeight + scrollTop) < this.bottomOffset;
    const emitValue: ScrollEvent = {
      isReachingBottom,
      isReachingTop,
      originalEvent: $event,
      isWindowEvent: true
    };
    this.onScroll.emit(emitValue);
  }

  protected elementScrollEvent($event: Event) {
    const target = <HTMLElement>$event.target;
    const scrollPosition = target.scrollHeight - target.scrollTop;
    const offsetHeight = target.offsetHeight;
    const isReachingTop = target.scrollTop < this.topOffset;
    const isReachingBottom = scrollPosition - offsetHeight < this.bottomOffset;
    const emitValue: ScrollEvent = {
      isReachingBottom,
      isReachingTop,
      originalEvent: $event,
      isWindowEvent: false
    };
    this.onScroll.emit(emitValue);
  }
}