直接上代码,有注释,简单小功能,好理解!
import { Directive,ElementRef,HostBinding,OnInit,Input } from '@angular/core';
import { fromEvent, merge, animationFrameScheduler, generate } from 'rxjs';
import { map, tap, throttleTime, debounceTime } from 'rxjs/operators';
import { TouchService } from './touch.service';
@Directive({
selector: '[dragmove]'
})
export class DragmoveDirective implements OnInit {
@HostBinding('style.left.px') _left: number;
@HostBinding('style.top.px') _top: number;
@HostBinding('style.position') _position: string = 'absolute';
// 如果设置了,那么记录位置,下次来的时候还原上一次操作位置
_cacheKey: string;
@Input()
set dragmove(val: string) {
if (val) {
this._cacheKey = val;
let p = localStorage.getItem(val);
if (p) {
let point = JSON.parse(p);
this._left = point.left;
this._top = point.top;
}
}
}
isStart: boolean = false;
constructor(public ele: ElementRef) {}
ngOnInit() {
this.onDrag();
}
onDrag() {
const mousemove = fromEvent(this.ele.nativeElement, 'mousemove');
const touchmove = fromEvent(this.ele.nativeElement, 'touchmove');
const nodeRect = this.ele.nativeElement.getBoundingClientRect();
const rect = {
height: nodeRect.height,
width: nodeRect.width
};
const move = merge(
mousemove.pipe(
map((evt: MouseEvent) => {
return {
x: evt.clientX,
y: evt.clientY
};
})
),
touchmove.pipe(
map((evt: TouchEvent) => {
return {
x: evt.touches[0].pageX,
y: evt.touches[0].pageY
};
})
),
animationFrameScheduler
).pipe(
map(res => {
this._top = res.y - rect.height / 2;
this._left = res.x - rect.width / 2;
return {
left: this._left,
top: this._top
};
}),
debounceTime(300),
tap(res => this._cacheKey && localStorage.setItem(this._cacheKey, JSON.stringify(res)))
);
move.subscribe((res: any) => {});
}
}
使用
<!--不带记忆功能-->
<div class="cube" dragmove></div>
<!--带记忆功能-->
<div class="cube" dragmove="dragmove-1"></div>
- 超级精简手势控件
import {
Directive,
OnInit,
ElementRef,
Input,
Output,
EventEmitter
} from '@angular/core';
import { fromEvent } from 'rxjs';
import { map, switchMap, takeUntil, debounceTime, tap } from 'rxjs/operators';
@Directive({
selector: '[swipeMove]'
})
export class SwipeMoveDirective implements OnInit {
// 移动像素临界值
@Output() swipeMove: EventEmitter<any> = new EventEmitter();
len: number = 10;
constructor(public ele: ElementRef) {}
ngOnInit() {
this.handler(this.ele.nativeElement);
}
handler(ele: Element) {
let start = fromEvent(ele, 'touchstart');
let move = fromEvent(ele, 'touchmove');
let end = fromEvent(ele, 'touchend');
document.oncontextmenu = () => false;
let t = (evt: TouchEvent) => ({
x: evt.touches[0].pageX,
y: evt.touches[0].pageY,
t: new Date().getTime(),
type: evt.type
});
// |start----------------------------
// -----------|move------------------
// --------------------------|end----
// |--------------|
start
.pipe(
// 规整
map(t),
switchMap(poi1 =>
move.pipe(
// 规整
map(t),
// 直到end
takeUntil(end),
map(end => ({
dx: end.x - poi1.x,
dy: end.y - poi1.y,
dt: end.t - poi1.t
})),
map(res => {
// x 主导
if (Math.abs(res.dx) > Math.abs(res.dy)) {
if (res.dx > this.len) return 'right';
else if (res.dx < -this.len) return 'left';
else return 'tap';
} else {
if (res.dy > this.len) return 'down';
else if (res.dy < -this.len) return 'up';
else return 'tap';
}
}),
tap(res=>this.swipeMove.next(res)),
debounceTime(100)
)
)
)
.subscribe(res => {});
}
}
<!--left right up down tap-->
<div class="cube" (swipeMove)="swipeMove($event)"></div>
小结
rxjs流式响应式编程的强大