Angular CDK-嵌套可滚动div中滚动和拖动元素的问题 [英] Angular CDK - issue with scrolling and dragging element inside nested scrollable div

查看:209
本文介绍了Angular CDK-嵌套可滚动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:

  1. 我们可以将固定高度和overflow: scroll设置为cdkDropList元素:
  1. We can set the fixed height and the overflow: scroll to the cdkDropList 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

  1. 如果我们无法使cdkDropList滚动,并且有一个父元素应该滚动(就像问题中的情况),我就改编了这里找到的解决方案( https://github.com/angular/components/issues/16677#issuecomment-562625427 ): 我们可以使用自定义指令cdkDropListScrollContainer,该指令将在cdkDrag元素上设置.该指令将对要滚动的父元素的引用作为Input:
  1. 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 directive cdkDropListScrollContainer, that will be set on the cdkDrag elements. This directive will take as a Input 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆