在 Angular 内滑动删除 10
Swipe to delete in Angular 10
你好我的开发伙伴。我只想请求帮助,以便在我们的 Angular 项目中实现滑动删除功能。
请看下面的截图。
这是我使用该功能的代码。
<div class="col-md-6 col-sm-6 col-xs-12" *ngFor="let relation of bookList" >
<div class="" (click)="selectBookFor(relation)">
<div class="">
<div class="row introMain-wrapper">
<div class="col-auto">
<div class="introImg">
<img src="{{ relation && relation.image }}" alt="user" (error)="setDefaultRelationUserPic($event, relation?.gender)">
</div>
</div>
<div class="col">
<div class="row">
<div class="col"><h5 class="card-title text">{{relation?.firstName}} {{relation?.lastName}}</h5></div>
<div class="col-auto"><span class="relation-text">{{relation?.relationship}}</span></div>
</div>
<h5 class="card-text">{{relation?.email}}</h5>
<div class="outerdiv-text">
<span class="card-text">{{relation?.phone1}}</span>
</div>
</div>
</div>
<div class="line"></div>
</div>
</div>
</div>
我试过以下插件:
- mat-list-touch
- 滑动-angular-列表
但在子模块中导入并提前在组件features.Thanks中使用时不起作用。
您可以使用 Angular material 拖放 https://material.angular.io/cdk/drag-drop/examples
由此,您可以创建滑动删除选项。
演示
<div class="container">
<div class="row">
<div
cdkDropList
cdkDropListSortingDisabled
[cdkDropListData]="bookList"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let item of bookList;let i= index" cdkDrag>{{item.firstName}}</div>
</div>
</div>
</div>
TS
drop(event: CdkDragDrop<any, any>): any {
this.bookList.splice(event.currentIndex, 1);
}
angular 支持事件 touchstart、touchend 和 touchmove。所以你可以想象这样一个指令:
export interface TouchEventType {
element: TouchDirective;
incrX: number;
incrY: number;
}
@Directive({
selector: '[touch]',
exportAs: 'touch'
})
export class TouchDirective {
origin: any = { x: 0, y: 0 };
style: any = null;
rect: any = { x: 0, y: 0 };
incrX: number = 0;
incrY: number = 0;
@Input('touch') direction: 'horizontal' | 'vertical' | null = null;
@Output() touchMove: EventEmitter<any> = new EventEmitter<any>();
@HostListener('touchstart', ['$event']) touchStart(event) {
this.origin = {
x: event.touches[0].screenX,
y: event.touches[0].screenY
};
}
@HostListener('touchmove', ['$event']) touch(event: TouchEvent) {
this.incrX = this.rect.x + event.touches[0].screenX - this.origin.x;
this.incrY = this.rect.y + event.touches[0].screenY - this.origin.y;
this.style =
this.direction == 'horizontal'
? {
transform: 'translateX(' + this.incrX + 'px)'
}
: this.direction == 'vertical'
? {
transform: 'translateY(' + this.incrY + 'px)'
}
: {
transform: 'translateY(' + this.incrX + 'px,' + this.incrY + 'px)'
};
if (this.direction)
window.scrollBy(this.direction=='horizontal'?
event.touches[0].screenX - this.origin.x:0,
this.direction=='vertical'?
event.touches[0].screenY - this.origin.y:0)
}
@HostListener('touchend', ['$event']) touchEnd() {
this.rect = { y: this.incrY, x: this.incrX };
this.touchMove.emit({
element: this,
incrX: this.incrX,
incrY: this.incrY
});
}
@HostBinding('style') get _() {
return this.style;
}
constructor(private elementRef: ElementRef) {}
reset() {
this.style = null;
this.rect = { x: 0, y: 0 };
}
}
您可以在 .html 中使用
<ng-container *ngFor="let item of array;let i=index">
<p touch='horizontal' (touchMove)="touchmove($event,i)">
Start editing to see some magic happen {{item}}
</p>
</ng-container>
array:any[]=[1,2,3,4,5,6,7]
touchmove(event:TouchEventType,index:number)
{
if (event.incrX<-10) //10px to the left
this.array.splice(index,1)
else
event.element.reset()
}
见stackblitz无任何保证
更新 如果我们想要在触摸屏和非触摸屏上工作,我们可以采用另一种方法。我们可以使用 fromEvent
rxjs 运算符来代替 @HostListener
。 (否则我们需要在 mousedown、mouseup 和 mousemove 上创建一个 hostListenr)
为了在时间上控制触摸事件和鼠标事件,我们使用 rxjs 合并运算符,它从两个 observable 接收值。要使用完全相同的代码,我们在触摸事件中使用“map”来转换 MouseEvent 中的响应(TouchEvent)。
最后一点是使用“点击”来了解是否是触摸屏。在触摸屏中,如果我们滑动 down/up,我们需要滚动 window dwon/up 我们的指令只允许水平移动
@Directive({
selector: '[touch]',
exportAs: 'touch'
})
export class TouchDirective {
origin: any = { x: 0, y: 0 };
style: any = null;
rect: any = { x: 0, y: 0 };
incrX: number = 0;
incrY: number = 0;
onDrag:boolean=false;
isTouched:boolean=false;
moveSubscription: any;
downSubscription: any;
@Input('touch') direction: 'horizontal' | 'vertical' | null = null;
@Output() touchMove: EventEmitter<any> = new EventEmitter<any>();
@HostBinding('style') get _() {
return this.style;
}
@HostBinding('class.no-select') get __() {
return this.onDrag;
}
constructor(private elementRef: ElementRef) {}
ngOnInit() {
this.downSubscription=merge(
fromEvent(this.elementRef.nativeElement, 'mousedown').pipe(tap(_=>this.isTouched=false)),
fromEvent(this.elementRef.nativeElement, 'touchstart').pipe(tap(_=>this.isTouched=true),
map((event: TouchEvent) => ({
target: event.target,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY
}))
)
).subscribe((event: MouseEvent) => {
//see that is the same code that @HostListener('touchstart', ['$event'])
this.origin = {
x: event.screenX,
y: event.screenY
};
this.onDrag=true;
merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend'))
.pipe(take(1))
.subscribe(() => {
//see that is the same code that @HostListener('touchend', ['$event'])
if (this.moveSubscription) {
this.moveSubscription.unsubscribe();
this.moveSubscription = undefined;
}
this.rect = { y: this.incrY, x: this.incrX };
this.touchMove.emit({
element: this,
incrX: this.incrX,
incrY: this.incrY
});
this.onDrag=false;
});
if (!this.moveSubscription) {
this.moveSubscription = merge(
fromEvent(document, 'mousemove'),
fromEvent(document, 'touchmove').pipe(
map((event: TouchEvent) => ({
target: event.target,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY
}))
))
.subscribe((event: MouseEvent) => {
//see that is the same code that @HostListener('touchmove', ['$event'])
this.incrX = this.rect.x + event.screenX - this.origin.x;
this.incrY = this.rect.y + event.screenY - this.origin.y;
this.style =
this.direction == 'horizontal'
? {
transform: 'translateX(' + this.incrX + 'px)'
}
: this.direction == 'vertical'
? {
transform: 'translateY(' + this.incrY + 'px)'
}
: {
transform: 'translateY(' + this.incrX + 'px,' + this.incrY + 'px)'
};
if (this.direction && this.isTouched)
window.scrollBy(
this.direction == 'horizontal'
? event.screenX - this.origin.x
: 0,
this.direction == 'vertical'
? event.screenY - this.origin.y
: 0
);
})
}
});
}
ngOnDestroy() {
this.downSubscription.unsubscribe();
}
reset() {
this.style = null;
this.rect = { x: 0, y: 0 };
}
}
我们添加 class
.no-select {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
在styles.css和
@HostBinding('class.no-select') get __() {
return this.onDrag;
}
当元素滑动时不select
stackblitz为touch/no触摸屏
开发人员大家好,感谢您的所有回答。顺便说一下,我使用 https://www.npmjs.com/package/swipe-angular-list 作为我的问题的解决方案。
你好我的开发伙伴。我只想请求帮助,以便在我们的 Angular 项目中实现滑动删除功能。
请看下面的截图。
这是我使用该功能的代码。
<div class="col-md-6 col-sm-6 col-xs-12" *ngFor="let relation of bookList" >
<div class="" (click)="selectBookFor(relation)">
<div class="">
<div class="row introMain-wrapper">
<div class="col-auto">
<div class="introImg">
<img src="{{ relation && relation.image }}" alt="user" (error)="setDefaultRelationUserPic($event, relation?.gender)">
</div>
</div>
<div class="col">
<div class="row">
<div class="col"><h5 class="card-title text">{{relation?.firstName}} {{relation?.lastName}}</h5></div>
<div class="col-auto"><span class="relation-text">{{relation?.relationship}}</span></div>
</div>
<h5 class="card-text">{{relation?.email}}</h5>
<div class="outerdiv-text">
<span class="card-text">{{relation?.phone1}}</span>
</div>
</div>
</div>
<div class="line"></div>
</div>
</div>
</div>
我试过以下插件:
- mat-list-touch
- 滑动-angular-列表
但在子模块中导入并提前在组件features.Thanks中使用时不起作用。
您可以使用 Angular material 拖放 https://material.angular.io/cdk/drag-drop/examples
由此,您可以创建滑动删除选项。
演示
<div class="container">
<div class="row">
<div
cdkDropList
cdkDropListSortingDisabled
[cdkDropListData]="bookList"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let item of bookList;let i= index" cdkDrag>{{item.firstName}}</div>
</div>
</div>
</div>
TS
drop(event: CdkDragDrop<any, any>): any {
this.bookList.splice(event.currentIndex, 1);
}
angular 支持事件 touchstart、touchend 和 touchmove。所以你可以想象这样一个指令:
export interface TouchEventType {
element: TouchDirective;
incrX: number;
incrY: number;
}
@Directive({
selector: '[touch]',
exportAs: 'touch'
})
export class TouchDirective {
origin: any = { x: 0, y: 0 };
style: any = null;
rect: any = { x: 0, y: 0 };
incrX: number = 0;
incrY: number = 0;
@Input('touch') direction: 'horizontal' | 'vertical' | null = null;
@Output() touchMove: EventEmitter<any> = new EventEmitter<any>();
@HostListener('touchstart', ['$event']) touchStart(event) {
this.origin = {
x: event.touches[0].screenX,
y: event.touches[0].screenY
};
}
@HostListener('touchmove', ['$event']) touch(event: TouchEvent) {
this.incrX = this.rect.x + event.touches[0].screenX - this.origin.x;
this.incrY = this.rect.y + event.touches[0].screenY - this.origin.y;
this.style =
this.direction == 'horizontal'
? {
transform: 'translateX(' + this.incrX + 'px)'
}
: this.direction == 'vertical'
? {
transform: 'translateY(' + this.incrY + 'px)'
}
: {
transform: 'translateY(' + this.incrX + 'px,' + this.incrY + 'px)'
};
if (this.direction)
window.scrollBy(this.direction=='horizontal'?
event.touches[0].screenX - this.origin.x:0,
this.direction=='vertical'?
event.touches[0].screenY - this.origin.y:0)
}
@HostListener('touchend', ['$event']) touchEnd() {
this.rect = { y: this.incrY, x: this.incrX };
this.touchMove.emit({
element: this,
incrX: this.incrX,
incrY: this.incrY
});
}
@HostBinding('style') get _() {
return this.style;
}
constructor(private elementRef: ElementRef) {}
reset() {
this.style = null;
this.rect = { x: 0, y: 0 };
}
}
您可以在 .html 中使用
<ng-container *ngFor="let item of array;let i=index">
<p touch='horizontal' (touchMove)="touchmove($event,i)">
Start editing to see some magic happen {{item}}
</p>
</ng-container>
array:any[]=[1,2,3,4,5,6,7]
touchmove(event:TouchEventType,index:number)
{
if (event.incrX<-10) //10px to the left
this.array.splice(index,1)
else
event.element.reset()
}
见stackblitz无任何保证
更新 如果我们想要在触摸屏和非触摸屏上工作,我们可以采用另一种方法。我们可以使用 fromEvent
rxjs 运算符来代替 @HostListener
。 (否则我们需要在 mousedown、mouseup 和 mousemove 上创建一个 hostListenr)
为了在时间上控制触摸事件和鼠标事件,我们使用 rxjs 合并运算符,它从两个 observable 接收值。要使用完全相同的代码,我们在触摸事件中使用“map”来转换 MouseEvent 中的响应(TouchEvent)。
最后一点是使用“点击”来了解是否是触摸屏。在触摸屏中,如果我们滑动 down/up,我们需要滚动 window dwon/up 我们的指令只允许水平移动
@Directive({
selector: '[touch]',
exportAs: 'touch'
})
export class TouchDirective {
origin: any = { x: 0, y: 0 };
style: any = null;
rect: any = { x: 0, y: 0 };
incrX: number = 0;
incrY: number = 0;
onDrag:boolean=false;
isTouched:boolean=false;
moveSubscription: any;
downSubscription: any;
@Input('touch') direction: 'horizontal' | 'vertical' | null = null;
@Output() touchMove: EventEmitter<any> = new EventEmitter<any>();
@HostBinding('style') get _() {
return this.style;
}
@HostBinding('class.no-select') get __() {
return this.onDrag;
}
constructor(private elementRef: ElementRef) {}
ngOnInit() {
this.downSubscription=merge(
fromEvent(this.elementRef.nativeElement, 'mousedown').pipe(tap(_=>this.isTouched=false)),
fromEvent(this.elementRef.nativeElement, 'touchstart').pipe(tap(_=>this.isTouched=true),
map((event: TouchEvent) => ({
target: event.target,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY
}))
)
).subscribe((event: MouseEvent) => {
//see that is the same code that @HostListener('touchstart', ['$event'])
this.origin = {
x: event.screenX,
y: event.screenY
};
this.onDrag=true;
merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend'))
.pipe(take(1))
.subscribe(() => {
//see that is the same code that @HostListener('touchend', ['$event'])
if (this.moveSubscription) {
this.moveSubscription.unsubscribe();
this.moveSubscription = undefined;
}
this.rect = { y: this.incrY, x: this.incrX };
this.touchMove.emit({
element: this,
incrX: this.incrX,
incrY: this.incrY
});
this.onDrag=false;
});
if (!this.moveSubscription) {
this.moveSubscription = merge(
fromEvent(document, 'mousemove'),
fromEvent(document, 'touchmove').pipe(
map((event: TouchEvent) => ({
target: event.target,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY
}))
))
.subscribe((event: MouseEvent) => {
//see that is the same code that @HostListener('touchmove', ['$event'])
this.incrX = this.rect.x + event.screenX - this.origin.x;
this.incrY = this.rect.y + event.screenY - this.origin.y;
this.style =
this.direction == 'horizontal'
? {
transform: 'translateX(' + this.incrX + 'px)'
}
: this.direction == 'vertical'
? {
transform: 'translateY(' + this.incrY + 'px)'
}
: {
transform: 'translateY(' + this.incrX + 'px,' + this.incrY + 'px)'
};
if (this.direction && this.isTouched)
window.scrollBy(
this.direction == 'horizontal'
? event.screenX - this.origin.x
: 0,
this.direction == 'vertical'
? event.screenY - this.origin.y
: 0
);
})
}
});
}
ngOnDestroy() {
this.downSubscription.unsubscribe();
}
reset() {
this.style = null;
this.rect = { x: 0, y: 0 };
}
}
我们添加 class
.no-select {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
在styles.css和
@HostBinding('class.no-select') get __() {
return this.onDrag;
}
当元素滑动时不select
stackblitz为touch/no触摸屏
开发人员大家好,感谢您的所有回答。顺便说一下,我使用 https://www.npmjs.com/package/swipe-angular-list 作为我的问题的解决方案。