滚动事件和Angular材质CDK拖放同时发生

时间:2018-11-29 13:25:11

标签: javascript angular

我正在使用以下应用程序:即时消息使用来自角材料cdk和perfect-scroll-bar.js的拖放(以更改容器中的滚动条),该应用程序需要支持触摸设备,而我在这里拖动事件和滚动事件的问题,我有一个包含2个项目列表的容器,一个容器有一个max-heightoverflow: hidden以在内容溢出的情况下显示滚动条,这些项目具有拖放功能来自cdk的指令,现在的问题是,在触摸设备中,当我尝试拖动元素时,容器会尝试同时滚动,同时拖动元素,移动列表并忽略元素i的位置拖着脚,有什么办法可以避免这种行为。

Todo-template.html

  <div class="detail-content-wrapper" perfecScrollbar>
    <div class="todo-list" cdkDropList #openList="cdkDropList" (cdkDropListDropped)="drop($event)">
        <div class="list-item" *ngFor="let todo of openTaskList; let i = index" [attr.position]="todo.position"
           cdkDrag>
          <div class="dd-placeholder" *cdkDragPlaceholder></div>
          <div class="state"></div>
          <div class="todo-text">
            <span class="task-text"> {{ todo.name }} </span>
            <input name="editToDoInput" class="form-control" value="{{todo.name}}" #editToDoInput />
          </div>
          <i class="fa fa-ellipsis-v drag-indicator"></i>
          <span class="icon-hype-close remove-icon" (click)="deleteTaskItem($event, todo, openTaskList, i)"></span>
        </div>
      </div>
    </div>      
  </div>

Perfec滚动指令

import { HypeConfigService } from './../services/config.service';
import { AfterViewInit, Directive, ElementRef, HostListener, OnDestroy, Input, Renderer2 } from '@angular/core';
import PerfectScrollbar from 'perfect-scrollbar';

@Directive({
  selector: '[perfectScrollbar]'
})
export class PerfectScrollbarDirective implements AfterViewInit, OnDestroy {
  isInitialized = true;
  pscrollbar: PerfectScrollbar;

  @Input() column: boolean = false;

  constructor(public element: ElementRef, private _render: Renderer2, private configService: HypeConfigService) {}

  ngAfterViewInit() {
    // Initialize the perfect-scrollbar
    this.pscrollbar = new PerfectScrollbar(this.element.nativeElement, {
      wheelPropagation: true,
      wheelSpeed: 2,
      suppressScrollX: this.column ? true : false
    });
    if (this.column) {
      if (this.configService.appConfig.IsUsingInternetExplorer || this.configService.appConfig.IsUsingMsEdge) {
        this.element.nativeElement.style.paddingRight = '0px';
        this.element.nativeElement.style.marginRight = '0px';
      } else {
        this.element.nativeElement.style.paddingRight = '18px';
        this.element.nativeElement.style.marginRight = this.configService.appConfig.IsUsingChrome ? '-18px' : '-24px';
      }
    }
  }

  ngOnDestroy() {
    if (!this.isInitialized || !this.pscrollbar) {
      return;
    }

    // Destroy the perfect-scrollbar
    this.pscrollbar.destroy();
  }

  @HostListener('document:click', ['$event'])
  documentClick(event: Event): void {
    if (!this.isInitialized || !this.pscrollbar) {
      return;
    }

    // Update the scrollbar on document click..
    // This isn't the most elegant solution but there is no other way
    // of knowing when the contents of the scrollable container changes.
    // Therefore, we update scrollbars on every document click.
    this.pscrollbar.update();
  }

  @HostListener('scroll', ['$event'])
  scrolling(event) {
    let element = this.element.nativeElement as HTMLElement;

    // A kanban column is the scrollable element
    if (element.attributes && element.attributes.getNamedItem('data-columnId')) {
      let parentElement = element.parentElement.parentElement;

      if (element.scrollTop > 0) {
        // If the user scrolls in a kanban column the element with css-class 'kanban-column' gets css-class 'scrolled'
        this._render.addClass(parentElement, 'scrolled');
      } else {
        // If scroll position is 0 (Zero) then remove the css-class on kanban column element
        if (parentElement && parentElement.className.indexOf('scrolled') > -1) {
          this._render.removeClass(parentElement, 'scrolled');
        }
      }
    } else {
      let parentElement = element.parentElement;

      if (element.scrollTop > 0) {
        // If the user scrolls in a kanban column the element with css-class 'kanban-column' gets css-class 'scrolled'
        this._render.addClass(parentElement, 'scrolled');
      } else {
        // If scroll position is 0 (Zero) then remove the css-class on kanban column element
        if (parentElement && parentElement.className.indexOf('scrolled') > -1) {
          this._render.removeClass(parentElement, 'scrolled');
        }
      }
    }
  }

  update() {
    if (!this.isInitialized) {
      return;
    }

    // Update the perfect-scrollbar
    this.pscrollbar.update();
  }

  destroy() {
    this.ngOnDestroy();
  }

  scrollToX(x: number, speed?: number) {
    this.animateScrolling('scrollLeft', x, speed);
  }

  scrollToY(y: number, speed?: number) {
    this.animateScrolling('scrollTop', y, speed);
  }

  scrollToTop(offset?: number, speed?: number) {
    this.animateScrolling('scrollTop', offset || 0, speed);
  }

  scrollToLeft(offset?: number, speed?: number) {
    this.animateScrolling('scrollLeft', offset || 0, speed);
  }

  scrollToRight(offset?: number, speed?: number) {
    const width = this.element.nativeElement.scrollWidth;

    this.animateScrolling('scrollLeft', width - (offset || 0), speed);
  }

  scrollToBottom(offset?: number, speed?: number) {
    const height = this.element.nativeElement.scrollHeight;

    this.animateScrolling('scrollTop', height - (offset || 0), speed);
  }

  animateScrolling(target: string, value: number, speed?: number) {
    if (!speed) {
      this.element.nativeElement[target] = value;

      // PS has weird event sending order, this is a workaround for that
      this.update();
      this.update();
    } else if (value !== this.element.nativeElement[target]) {
      let newValue = 0;
      let scrollCount = 0;

      let oldTimestamp = performance.now();
      let oldValue = this.element.nativeElement[target];

      const cosParameter = (oldValue - value) / 2;

      const step = (newTimestamp) => {
        scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp));

        newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));

        // Only continue animation if scroll position has not changed
        if (this.element.nativeElement[target] === oldValue) {
          if (scrollCount >= Math.PI) {
            this.element.nativeElement[target] = value;

            // PS has weird event sending order, this is a workaround for that
            this.update();

            this.update();
          } else {
            this.element.nativeElement[target] = oldValue = newValue;

            oldTimestamp = newTimestamp;

            window.requestAnimationFrame(step);
          }
        }
      };

      window.requestAnimationFrame(step);
    }
  }
}

0 个答案:

没有答案