Я работаю в приложении, где я использую перетаскивание из углового материала cdk и perfect-scroll-bar.js (чтобы изменить полосу прокрутки в моем контейнере), приложение должно поддерживать сенсорные устройства, и вот где у меня естьпроблема с событием перетаскивания и событием прокрутки, у меня есть контейнер, который имеет 2 списка элементов, контейнер имеет max-height
и overflow: hidden
для отображения полосы прокрутки в случае переполнения содержимого, эти элементы имеют директиву drag & drop из cdkТеперь проблема заключается в том, что в сенсорных устройствах, когда я пытаюсь перетащить элементы, контейнер пытается прокрутить одновременно, я перетаскиваю элемент, перемещая список и теряя из виду положение элемента, который я перетаскиваю,Есть ли способ избежать этого поведения.
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);
}
}
}