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