Angular CDK - 在嵌套的可滚​​动 div 内滚动和拖动元素的问题

Posted

技术标签:

【中文标题】Angular CDK - 在嵌套的可滚​​动 div 内滚动和拖动元素的问题【英文标题】:Angular CDK - issue with scrolling and dragging element inside nested scrollable div 【发布时间】:2020-01-05 09:12:36 【问题描述】:

先决条件:cdk 嵌套可滚动元素内的可拖动元素div (见example)

如何重现:

    开始拖动项目。 滚动页面 不滚动时多拖一点

效果:项目占位符停留在错误的位置,基本上不可能将项目拖到视口之外的任何地方。

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

【问题讨论】:

可滚动div的虚拟滚动cdk试过了吗? 我遇到了同样的问题。你有没有找到解决方案? 有人有解决办法吗? 【参考方案1】:

我在Angular components' official Github repository搜索了这个问题,发现了以下主题:

https://github.com/angular/components/issues/13588

https://github.com/angular/components/issues/16535

根据您使用的版本,有不同的解决方案:Angular 9+(也适用于 Angular 10)或 Angular 8

Angular 9+(也适用于 Angular 10)

9.1.0 版本开始,通过设置 cdkScrollable 指令来支持父元素的滚动。

因此,对于 v9.1.0 及更高版本,以下代码应该可以工作:

<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

8.1.0 版本开始,启用了滚动,但适用于 cdkDropList 本身视口(出于性能原因)。所以有两种解决方案:

    我们可以将固定高度和overflow: scroll设置为cdkDropList元素:
<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 可滚动并且有一个父元素应该滚动(就像问题中的情况),我已经调整了一个在这里找到的解决方案 (@987654327 @): 我们可以使用自定义指令cdkDropListScrollContainer,它将在cdkDrag 元素上设置。该指令将作为 Input 对应该滚动的父元素的引用:
<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

【讨论】:

在使用指令方法时,我收到错误消息“无法分配给‘元素’,因为它是只读属性。”对于行“cdkDropList._dropListRef.element = element”和“cdkDropList._dropListRef.element = cdkDropList.element.nativeElement”

以上是关于Angular CDK - 在嵌套的可滚​​动 div 内滚动和拖动元素的问题的主要内容,如果未能解决你的问题,请参考以下文章

angular中安装@angular/cdk时遇到的错误——node_modules/@angular/cdk/table/table.d.ts:277:9 - error TS1086: An ac

angular中安装@angular/cdk时遇到的错误——node_modules/@angular/cdk/table/table.d.ts:277:9 - error TS1086: An ac

angular中安装@angular/cdk时遇到的错误——node_modules/@angular/cdk/table/table.d.ts:277:9 - error TS1086: An ac

angular中安装@angular/cdk时遇到的错误——node_modules/@angular/cdk/table/table.d.ts:277:9 - error TS1086: An ac

嵌套情况下的cdk拖放

错误:非法状态:无法在 node_modules/@angular/cdk/observers/typings/index.d.ts 中加载指令 CdkObserveContent 的摘要