You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在拖拽mat tabs时结合cdk drag drop实现自动滚动?

解决Mat Tab与CDK Drag Drop结合时自动滚动失效问题

问题分析

默认CDK拖拽自动滚动失效,通常是因为mat-tab-nav-bar的样式结构干扰了CDK对滚动容器的识别,或者未正确关联拖拽事件与滚动逻辑。以下是具体解决方案:


步骤1:调整模板结构与事件绑定

修改模板,移除自定义wheel事件,添加CDK拖拽的开始、移动事件绑定,确保滚动容器的样式正确:

<div
  #docTabGroup
  mat-tab-nav-bar
  cdkDropList
  cdkScrollable
  cdkDropListOrientation="horizontal"
  class="example-list"
  (cdkDropListDropped)="drop($event)"
>
  <div
    mat-tab-link
    class="example-box"
    *ngFor="let timePeriod of timePeriods"
    cdkDrag
    (cdkDragStarted)="onDragStarted()"
    (cdkDragMoved)="onDragMoved($event)"
  >
    {{timePeriod}}
  </div>
</div>

步骤2:实现拖拽时的自动滚动逻辑

在组件类中注入ScrollDispatcher,通过监听拖拽事件,根据鼠标位置触发容器滚动:

import { Component, ViewChild, ElementRef } from '@angular/core';
import { CdkDragDrop } from '@angular/cdk/drag-drop';

@Component({
  selector: 'app-tab-drag-example',
  templateUrl: './tab-drag-example.html',
  styleUrls: ['./tab-drag-example.css']
})
export class TabDragExampleComponent {
  timePeriods = ['Morning', 'Afternoon', 'Evening', 'Night', 'Weekend', 'Holiday', 'Workday', 'Vacation'];
  
  @ViewChild('docTabGroup') tabGroup!: ElementRef<HTMLElement>;
  private scrollInterval: any;

  onDragStarted() {
    // 初始化拖拽状态
  }

  onDragMoved(event: any) {
    const scrollContainer = this.tabGroup.nativeElement;
    const mouseX = event.pointerPosition.x;
    const containerRect = scrollContainer.getBoundingClientRect();
    const scrollThreshold = 50; // 距离边缘50px触发滚动
    let scrollSpeed = 0;

    // 判断滚动方向
    if (mouseX < containerRect.left + scrollThreshold) {
      scrollSpeed = -5;
    } else if (mouseX > containerRect.right - scrollThreshold) {
      scrollSpeed = 5;
    }

    // 执行滚动
    if (this.scrollInterval) clearInterval(this.scrollInterval);
    this.scrollInterval = setInterval(() => {
      scrollContainer.scrollLeft += scrollSpeed;
    }, 16);
  }

  drop(event: CdkDragDrop<string[]>) {
    // 拖拽排序逻辑
    const item = this.timePeriods.splice(event.previousIndex, 1)[0];
    this.timePeriods.splice(event.currentIndex, 0, item);
    // 停止滚动
    if (this.scrollInterval) {
      clearInterval(this.scrollInterval);
      this.scrollInterval = null;
    }
  }
}

步骤3:设置容器样式

确保滚动容器具备横向滚动的基础样式:

.example-list {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 8px;
  white-space: nowrap;
  /* 隐藏滚动条(可选) */
  scrollbar-width: none;
}
.example-list::-webkit-scrollbar {
  display: none;
}

.example-box {
  padding: 12px 24px;
  background: #fff;
  border: 1px solid #ccc;
  cursor: grab;
}

.example-box.cdk-drag-preview {
  box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

核心要点

  • 通过cdkDragMoved事件实时获取鼠标位置,判断是否触发滚动
  • 使用定时器实现平滑滚动,模拟CDK原生自动滚动效果
  • 确保滚动容器的overflow-x: auto样式正确生效,为滚动提供基础条件

内容的提问来源于stack exchange,提问作者Sa Hagin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 08:08:31