Angular CDK-嵌套可滚动div中滚动和拖动元素的问题 [英] Angular CDK - issue with scrolling and dragging element inside nested scrollable div
问题描述
先决条件:嵌套可滚动div中的cdk可拖动元素 (请参见示例 https://stackblitz .com/edit/angular-7y19nm?file = app/cdk-drag-drop-sorting-example.html )
Prerequisite: cdk draggable elements inside a nested scrollable div (see the example https://stackblitz.com/edit/angular-7y19nm?file=app/cdk-drag-drop-sorting-example.html)
如何复制:开始拖动项目->滚动页面->不滚动时再拖动项目
How to reproduce: Start dragging an item -> scroll the page -> drag item a bit more when not scrolling
效果:项目占位符停留在错误的位置,基本上不可能将项目拖到视口之外的任何地方.
Effect: item placeholder stays in wrong place and it's basically impossible to drag item anywhere outside the viewport.
<div style="height: 100vh; overflow-y: auto">
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let movie of movies" cdkDrag>{{movie}}</div>
</div>
</div>
推荐答案
我已经在 Angular组件的官方Github存储库,我发现了以下主题:
I've searched for this issue in the Angular components' official Github repository and I have found the following topics:
https://github.com/angular/components/issues/16535
根据您使用的版本,有不同的解决方案: Angular 9 + (还可以与 Angular 10 一起使用)或 Angular 8 :
There are different solutions depending on the version that you use: Angular 9+ (works also with Angular 10) or Angular 8:
从版本 9.1.0 开始,通过将cdkScrollable
指令设置为父元素来支持滚动父元素.
From version 9.1.0, the scrolling of the parent element is supported by setting the cdkScrollable
directive to it.
因此,对于v9.1.0及更高版本,以下代码应该有效:
So, for v9.1.0 and up, the following code should work:
<div style="height: 100vh; overflow-y: auto" cdkScrollable>
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let movie of movies" cdkDrag>{{movie}}</div>
</div>
</div>
Stackblitz演示:
https://stackblitz.com/edit/angular-swaqkk-yjiz7r (使用v10.0.1 )
https://stackblitz.com/edit/angular-vszdat (使用v9.2.4 )
从版本 8.1.0 开始,启用了滚动,但仅用于 cdkDropList本身或视口 >(出于性能原因).因此,有两种解决方案可用:
From version 8.1.0, the scrolling was enabled, but only for the cdkDropList itself or the viewport (for performance reasons). So there are two solutions available:
- 我们可以将固定高度和
overflow: scroll
设置为cdkDropList
元素:
- We can set the fixed height and the
overflow: scroll
to thecdkDropList
element:
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)" style="height: 100vh; overflow-y: auto">
<div class="example-box" *ngFor="let movie of movies" cdkDrag>{{movie}}
</div>
</div>
Stackblitz演示:
https://stackblitz.com/edit/angular-avezy6
- 如果我们无法使
cdkDropList
滚动,并且有一个父元素应该滚动(就像问题中的情况),我就改编了这里找到的解决方案( https://github.com/angular/components/issues/16677#issuecomment-562625427 ): 我们可以使用自定义指令cdkDropListScrollContainer
,该指令将在cdkDrag
元素上设置.该指令将对要滚动的父元素的引用作为Input
:
- If we can't make the
cdkDropList
scrollable and there is a parent element that should scroll (like the situation in the question), I've adapted a solution found here (https://github.com/angular/components/issues/16677#issuecomment-562625427): we can use a custom directivecdkDropListScrollContainer
, that will be set on thecdkDrag
elements. This directive will take as aInput
the reference to the parent element that should scroll:
<div class="example-container" style="height: 500px; overflow-y: auto" #scrollContainer>
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
<div
class="example-box"
*ngFor="let movie of movies"
cdkDrag
[cdkDropListScrollContainer]="scrollContainer">
{{movie}}
</div>
</div>
</div>
该指令的代码为:
import { Directive, Input, ElementRef } from "@angular/core";
import { CdkDrag } from "@angular/cdk/drag-drop";
@Directive({
selector: "[cdkDropListScrollContainer]"
})
export class CdkDropListScrollContainerDirective {
@Input("cdkDropListScrollContainer") scrollContainer: HTMLElement;
originalElement: ElementRef<HTMLElement>;
constructor(cdkDrag: CdkDrag) {
cdkDrag._dragRef.beforeStarted.subscribe(() => {
const cdkDropList = cdkDrag.dropContainer;
if (!this.originalElement) {
this.originalElement = cdkDropList.element;
}
if (this.scrollContainer) {
const element = this.scrollContainer;
cdkDropList._dropListRef.element = element;
cdkDropList.element = new ElementRef<HTMLElement>(element);
} else {
cdkDropList._dropListRef.element = cdkDropList.element.nativeElement;
cdkDropList.element = this.originalElement;
}
});
}
}
Stackblitz演示: https://stackblitz.com/edit/angular-jkuqhg
这篇关于Angular CDK-嵌套可滚动div中滚动和拖动元素的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!