在 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>

我试过以下插件:

但在子模块中导入并提前在组件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 作为我的问题的解决方案。