Requirement 1: Obtain mouse click or finger touch position data

Analysis: Unordered merge

import { Directive, ElementRef, Output, EventEmitter } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { fromEvent } from "rxjs/observable/fromEvent";
import { merge } from "rxjs/observable/merge";
// Requirement 1: Get position data of mouse click or finger touch

@Directive({
  selector: "[getTouchendOrMouseupPosition]"
})
export class GetTouchendOrMouseupPositionDirective {
  @Output()
  getTouchendOrMouseupPosition: EventEmitter<{
    x: number;
    y: number; } > =new EventEmitter();
  constructor(public ele: ElementRef) {}

  ngOnInit() {
    this.getEndPosition().subscribe(res= > {
      this.getTouchendOrMouseupPosition.emit(res);
    });
  }
  getEndPosition(): Observable<{ x: number; y: number} > {let ele = this.ele.nativeElement;
    let mouseup = fromEvent(ele, "mouseup").map((ev: any) = > ({
      x: ev.clientX,
      y: ev.clientY
    }));
    let touchend = fromEvent(ele, "touchend").map((ev: any) = > ({
      x: ev.changedTouches[0].clientX,
      y: ev.changedTouches[0].clientY
    }));
    let mouseupAndTouchEnd = merge(mouseup, touchend);
    returnmouseupAndTouchEnd; }}Copy the code
  • use
<div style="width: 300px; height: 300px; background-color: red;" (getTouchendOrMouseupPosition) ="getTouchendOrMouseupPosition($event)"></div>
Copy the code
getTouchendOrMouseupPosition(e: {x:number,y: number{})console.log('The last position is:',e);
}
Copy the code

Requirement 2: Print verbatim

Analysis: Recursive processing

import {
  Directive,
  Input,
  ElementRef,
  EventEmitter,
  Output
} from "@angular/core";
import { from } from "rxjs/observable/from";
import { interval } from "rxjs/observable/interval";
import "rxjs/add/operator/scan";
import "rxjs/add/operator/zip";

@Directive({
  selector: "[writeWordByString]"
})
export class WriteWordByStringDirective {
  // The written character
  @Input() writeWordByString: string;
  // Writing speed
  @Input() writeSpeed: number = 200;
  @Input() writeLoop: boolean = false;
  // Return the processing result
  @Output() onWrite: EventEmitter<string> = new EventEmitter();
  constructor(public ele: ElementRef) {}
  ngOnInit() {
    this.getByWord();
  }
  getByWord() {
    let word = from<string> (this.writeWordByString)
      .zip(interval(this.writeSpeed), (x, y) = > x)
      .scan((origin, next) = > origin + next);
    word.subscribe(
      res= > {
        this.onWrite.emit(res);
      },
      (a)= > {},
      (a)= > {
        this.getByWord(); }); }}Copy the code
  • use
<div style="color: #fff;" (onWrite) ="str = $event" writeWordByString="Hello everyone, welcome to use mibo background management system! I'm Xiao Ming who developed this system. My QQ number is 1037483576. If there are bugs, remember to feedback me!">{{str}}</div>
Copy the code

Requirement 3: Keyword search

Analysis: Remove unwanted HTTP requests

import {
  Directive,
  Input,
  ElementRef,
  EventEmitter,
  Output
} from "@angular/core";
import { fromEvent } from "rxjs/observable/fromEvent";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/pluck";
import "rxjs/add/operator/filter";

import { HttpClient } from "@angular/common/http";

@Directive({
  selector: "[searchByKeyword]"
})
export class SearchByKeywordDirective {
  / / request url
  @Input() searchByKeyword: string;
  @Input() searchKey: string = "key";
  @Output() onSearch: EventEmitter<any> = new EventEmitter();
  constructor(public ele: ElementRef, public http: HttpClient) {}
  ngOnInit() {
    if (this.searchByKeyword.indexOf("?") > - 1) {
      // If yes? Don't deal with
    } else {
      this.searchByKeyword += `?${this.searchKey}= `;
    }
    this.doOnSearch();
  }
  doOnSearch() {
    fromEvent(this.ele.nativeElement, "keyup")
      .debounceTime(300)
      .pluck("target"."value")
      // Remove invalid keywords
      .filter((text) = >!!!!! text) .switchMap(key= > this.http.get(this.searchByKeyword + key))
      .subscribe(res= > {
        this.onSearch.emit(res); }); }}Copy the code
  • use
<input type="text" searchByKeyword="http://api.jirengu.com/fm/getSong.php?key=">
Copy the code

You need to create an element that can be dragged and dropped at will

import {
  Directive,
  ElementRef,
  Renderer2,
  Input,
  HostBinding
} from "@angular/core";
import { fromEvent } from "rxjs/observable/fromEvent";
import { merge } from "rxjs/observable/merge";

import "rxjs/add/operator/switchMap";
import "rxjs/add/operator/map";
import "rxjs/add/operator/takeUntil";
import "rxjs/add/operator/throttle";
import "rxjs/add/operator/pairwise";
import "rxjs/add/operator/do";

@Directive({
  selector: "[dragToMove]"
})
export class DragToMoveDirective {
  @HostBinding("style.position") _position: string;
  @HostBinding("style.left.px") _left: number;
  @HostBinding("style.top.px") _top: number;

  @Input("dragToMove")
  set position(val) {
    if (val) {
      this._position = val; }}get position() {
    return this._position || "absolute";
  }
  constructor(public ele: ElementRef, public render: Renderer2) {}

  ngOnInit() {
    this.drag()
      .do((pos: any) = > {
        this._position = this.position;
        this._left = pos.left;
        this._top = pos.top;
      })
      .subscribe(pos= > {});
  }

  mousedrag() {
    return this.mousedown().switchMap((md: MouseEvent) = > {
      const startX = md.offsetX;
      const startY = md.offsetY;
      return this.mousemove()
        .map((mm: MouseEvent) = > {
          mm.preventDefault();
          return {
            left: mm.clientX - startX,
            top: mm.clientY - startY
          };
        })
        .takeUntil(this.mouseup());
    });
  }

  touchdrag() {
    return this.touchstart().switchMap((ts: TouchEvent) = > {
      const rect = this.getBoundingClientRect();
      const startX = ts.targetTouches[0].clientX - rect.left;
      const startY = ts.targetTouches[0].clientY - rect.top;
      return this.touchmove()
        .map((tm: TouchEvent) = > {
          tm.preventDefault();
          return {
            left: tm.targetTouches[0].clientX - startX,
            top: tm.targetTouches[0].clientY - startY
          };
        })
        .takeUntil(this.touchend());
    });
  }

  mousemove() {
    return fromEvent(document."mousemove");
  }

  touchmove() {
    return fromEvent(document."touchmove");
  }

  mousedown() {
    return fromEvent(this.ele.nativeElement, "mousedown");
  }

  touchstart() {
    return fromEvent(this.ele.nativeElement, "touchstart");
  }

  mouseup() {
    return fromEvent(document."mouseup");
  }

  touchend() {
    return fromEvent(document."touchend");
  }

  drag() {
    return merge(this.mousedrag(), this.touchdrag());
  }

  getBoundingClientRect() {
    return this.ele.nativeElement.getBoundingClientRect(); }}Copy the code
  • use
<div dragToMove style=" display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; height: 200px; width: 200px; background: red; ">I can drag it</div>
Copy the code

Stop listening when four onDestory is required

In Angular, an Observable does some cleanup when a component logs out. The common way to do this is to store all observations in an array or a map, or something like that. Unsubscribe is a very unappealing way to iterate onDestory. Now let’s look at a proper posture.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject, merge, timer, interval } from 'rxjs';
import { takeUntil, filter, map } from 'rxjs/operators';
@Component({
  selector: 'ramda',
  templateUrl: './ramda.component.html',
  styleUrls: ['./ramda.component.scss']})export class RamdaComponent implements OnInit, OnDestroy {
  // subscribe to event 1
  sub: Subject<any> = new Subject();
  // subscribe to event 2
  sub2: Subject<any> = new Subject();
  // subscribe to event 3
  sub3: Subject<any> = new Subject();
  // subscribe to event 4
  sub4: Subject<any> = new Subject();
  // The unsubscribe switch is required
  needDestory: boolean = false;
  constructor() {}

  ngOnDestroy() {
    this.needDestory = true;
  }

  ngOnInit() {
    this.needDestory = false;
    let takeUtil$ = merge(this.sub, this.sub2, this.sub3, this.sub4).pipe(
      filter(val= > this.needDestory)
    );
    let sub = this.sub.pipe(takeUntil(takeUtil$)).subscribe(res= > {
      // get the desired result 0,1,2,3,4,5 seconds after the simulation logout component,2s after the simulation back,5,6,7,8
      this.log(res);
    });
    let sub2 = this.sub2.pipe(takeUntil(takeUtil$)).subscribe(res= > {
    // get the desired result 100,101,102,103,104,5 seconds after the simulation logout component,2s after the simulation come back,105,106,107,108
      this.log(res);
    });
    // Simulate event publishing
    interval(1000)
      .pipe(takeUntil(takeUtil$))
      .subscribe(res= > {
        this.sub.next(res);
        this.sub2.next(100 + res);
      });

    timer(5000).subscribe(res= > {
      this.log('Simulate logout component after 5s');
      this.ngOnDestroy();
      timer(200).subscribe(res= > {
        this.log('Simulation comes back in 2s.');
        this.needDestory = false;
      });
    });
  }

  log(msg) {
    console.log(msg); }}Copy the code

summary

filter

  • Take Takes the first N intercepts
  • TakeUntil Intercepts the stream until it is emitted
  • TakeWhile intercepts the stream until false
  • Skip the first N
  • SkipUntil skips until the stream is emitted
  • SkipWhild skips until false
  • Take a single
  • The sample of sampling
  • Last, the last
  • First takes the value of the first or the first one that satisfies the condition
  • Filter The filtering conditions are met
  • Debounce Indicates a dynamic time segment
  • DebounceTime Indicates the time range
  • IgnoreElements ignores everything else except Complement and error
  • Throttle orifice
  • ThrottleTime Time elapsed after the latest value

conversion

  • Pluck property selection
  • Buffer specifies whether a stream is emitted
  • BufferCount is emitted when it reaches a specified length
  • BufferTime is emitted when the specified time is reached
  • bufferToggle
  • bufferWhen
  • GroupBy grouping
  • Partition division
  • Scan time lapse

What do you need, message together to solve!