AngularCDK集成技能Skill angular-cdk-integration

Angular CDK集成技能是专门为ng-events项目设计的开发指南,详细介绍了如何使用Angular CDK工具包中的核心模块。该技能涵盖拖放功能实现、覆盖层创建、虚拟滚动优化、剪贴板操作、平台检测等关键技术。通过代码示例和最佳实践,帮助开发者构建高性能、无障碍的Angular应用界面。关键词:Angular CDK, 拖放功能, 虚拟滚动, 覆盖层, 无障碍设计, 前端开发, Angular组件

前端开发 0 次安装 0 次浏览 更新于 2/28/2026

名称: angular-cdk-integration 描述: 为ng-events项目创建使用Angular CDK工具(包括拖放、覆盖层、门户、滚动、无障碍、剪贴板和平台检测)的组件 许可证: MIT

Angular CDK集成技能

本技能指导在ng-events施工管理系统项目中,使用Angular CDK (@angular/cdk)工具创建组件和功能。

何时使用此技能

触发词: “Angular CDK”、“拖放”、“覆盖层”、“门户”、“虚拟滚动”、“无障碍”、“剪贴板”、“平台检测”、“CDK工具”

在以下场景使用此技能:

  • 实现拖放功能
  • 创建覆盖层、工具提示或弹出框
  • 构建虚拟滚动列表
  • 管理焦点和无障碍功能
  • 检测平台/浏览器能力
  • 处理剪贴板操作
  • 管理滚动行为

核心CDK模块

1. 拖放 (@angular/cdk/drag-drop)

目的: 创建可拖拽元素和放置区域

import { Component } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { CommonModule } from '@angular/common';
import { CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';

@Component({
  selector: 'app-task-board',
  standalone: true,
  imports: [CommonModule, CdkDropList, CdkDrag],
  template: `
    <div class="task-board">
      <div class="column" cdkDropList #todoList="cdkDropList"
           [cdkDropListData]="todo"
           [cdkDropListConnectedTo]="[inProgressList, doneList]"
           (cdkDropListDropped)="drop($event)">
        <h3>待办</h3>
        @for (task of todo; track task.id) {
          <div cdkDrag class="task-card">
            {{ task.title }}
            <div *cdkDragPlaceholder class="drag-placeholder"></div>
          </div>
        }
      </div>
      
      <div class="column" cdkDropList #inProgressList="cdkDropList"
           [cdkDropListData]="inProgress"
           [cdkDropListConnectedTo]="[todoList, doneList]"
           (cdkDropListDropped)="drop($event)">
        <h3>进行中</h3>
        @for (task of inProgress; track task.id) {
          <div cdkDrag class="task-card">{{ task.title }}</div>
        }
      </div>
      
      <div class="column" cdkDropList #doneList="cdkDropList"
           [cdkDropListData]="done"
           [cdkDropListConnectedTo]="[todoList, inProgressList]"
           (cdkDropListDropped)="drop($event)">
        <h3>已完成</h3>
        @for (task of done; track task.id) {
          <div cdkDrag class="task-card">{{ task.title }}</div>
        }
      </div>
    </div>
  `,
  styles: [`
    .task-board {
      display: flex;
      gap: 20px;
    }
    
    .column {
      flex: 1;
      min-height: 400px;
      background: #f5f5f5;
      padding: 16px;
      border-radius: 4px;
    }
    
    .task-card {
      background: white;
      padding: 12px;
      margin-bottom: 8px;
      border-radius: 4px;
      cursor: move;
    }
    
    .task-card:active {
      box-shadow: 0 5px 5px -3px rgba(0,0,0,.2);
    }
    
    .drag-placeholder {
      background: #ccc;
      border: dotted 2px #999;
      height: 40px;
      transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
    }
  `]
})
export class TaskBoardComponent {
  todo = [
    { id: '1', title: '任务1' },
    { id: '2', title: '任务2' }
  ];
  
  inProgress = [
    { id: '3', title: '任务3' }
  ];
  
  done = [
    { id: '4', title: '任务4' }
  ];
  
  drop(event: CdkDragDrop<Task[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    } else {
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    }
  }
}

2. 覆盖层 (@angular/cdk/overlay)

目的: 创建浮动面板和弹出窗口

import { Component, inject } from '@angular/core';
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';

@Component({
  selector: 'app-menu-trigger',
  standalone: true,
  template: `
    <button (click)="openMenu()">打开菜单</button>
  `
})
export class MenuTriggerComponent {
  private overlay = inject(Overlay);
  private overlayRef: OverlayRef | null = null;
  
  openMenu(): void {
    if (this.overlayRef) {
      this.overlayRef.dispose();
      this.overlayRef = null;
      return;
    }
    
    const positionStrategy = this.overlay
      .position()
      .flexibleConnectedTo(this.elementRef)
      .withPositions([
        {
          originX: 'start',
          originY: 'bottom',
          overlayX: 'start',
          overlayY: 'top'
        }
      ]);
    
    this.overlayRef = this.overlay.create({
      positionStrategy,
      scrollStrategy: this.overlay.scrollStrategies.reposition(),
      hasBackdrop: true,
      backdropClass: 'cdk-overlay-transparent-backdrop'
    });
    
    const menuPortal = new ComponentPortal(MenuComponent);
    this.overlayRef.attach(menuPortal);
    
    // 点击背景关闭
    this.overlayRef.backdropClick().subscribe(() => {
      this.overlayRef?.dispose();
      this.overlayRef = null;
    });
  }
}

3. 虚拟滚动 (@angular/cdk/scrolling)

目的: 高效渲染大型列表

import { Component, signal } from '@angular/core';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-task-list-virtual',
  standalone: true,
  imports: [CommonModule, ScrollingModule],
  template: `
    <cdk-virtual-scroll-viewport itemSize="50" class="viewport">
      <div *cdkVirtualFor="let task of tasks()" class="task-item">
        <h4>{{ task.title }}</h4>
        <p>{{ task.description }}</p>
      </div>
    </cdk-virtual-scroll-viewport>
  `,
  styles: [`
    .viewport {
      height: 400px;
      width: 100%;
      border: 1px solid #ccc;
    }
    
    .task-item {
      height: 50px;
      padding: 10px;
      border-bottom: 1px solid #eee;
    }
  `]
})
export class TaskListVirtualComponent {
  tasks = signal(Array.from({ length: 10000 }, (_, i) => ({
    id: `task-${i}`,
    title: `任务 ${i}`,
    description: `任务 ${i} 的描述`
  })));
}

4. 剪贴板 (@angular/cdk/clipboard)

目的: 复制文本到剪贴板

import { Component, inject } from '@angular/core';
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard';

@Component({
  selector: 'app-share-link',
  standalone: true,
  imports: [ClipboardModule],
  template: `
    <div class="share-container">
      <input [value]="shareLink" readonly #linkInput />
      <button 
        [cdkCopyToClipboard]="shareLink"
        (cdkCopyToClipboardCopied)="onCopied($event)">
        复制链接
      </button>
      @if (copied) {
        <span class="success">已复制!</span>
      }
    </div>
  `
})
export class ShareLinkComponent {
  private clipboard = inject(Clipboard);
  shareLink = 'https://ng-events.com/blueprints/123';
  copied = false;
  
  onCopied(success: boolean): void {
    if (success) {
      this.copied = true;
      setTimeout(() => this.copied = false, 2000);
    }
  }
}

5. 平台检测 (@angular/cdk/platform)

目的: 检测浏览器和平台能力

import { Component, inject, OnInit } from '@angular/core';
import { Platform } from '@angular/cdk/platform';

@Component({
  selector: 'app-platform-aware',
  standalone: true,
  template: `
    <div class="platform-info">
      <h3>平台信息</h3>
      <ul>
        <li>浏览器: {{ browser }}</li>
        <li>移动端: {{ isMobile }}</li>
        <li>iOS: {{ isIOS }}</li>
        <li>Android: {{ isAndroid }}</li>
      </ul>
    </div>
  `
})
export class PlatformAwareComponent implements OnInit {
  private platform = inject(Platform);
  
  browser = '';
  isMobile = false;
  isIOS = false;
  isAndroid = false;
  
  ngOnInit(): void {
    this.isMobile = this.platform.IOS || this.platform.ANDROID;
    this.isIOS = this.platform.IOS;
    this.isAndroid = this.platform.ANDROID;
    
    if (this.platform.FIREFOX) this.browser = 'Firefox';
    else if (this.platform.EDGE) this.browser = 'Edge';
    else if (this.platform.SAFARI) this.browser = 'Safari';
    else if (this.platform.WEBKIT) this.browser = 'WebKit';
    else this.browser = '未知';
  }
}

集成检查清单

使用Angular CDK时:

  • [ ] 导入特定CDK模块(非完整@angular/cdk)
  • [ ] 使用独立组件配合CDK指令
  • [ ] 实现适当的清理(订阅、覆盖层)
  • [ ] 使用屏幕阅读器测试无障碍性
  • [ ] 处理移动端/触摸交互
  • [ ] 考虑性能(超过100项的列表使用虚拟滚动)
  • [ ] 需要时与Blueprint多租户集成
  • [ ] 遵循三层架构(CDK仅在UI层使用)

最佳实践

推荐 ✅

  • 使用CDK处理复杂UI交互
  • 对大型数据集使用虚拟滚动
  • 使用覆盖层服务处理工具提示/菜单
  • 检测平台以支持功能
  • 销毁时清理覆盖层和门户

不推荐 ❌

  • 在服务或仓库中使用CDK(仅限UI层)
  • 创建没有清理逻辑的覆盖层
  • 忽略无障碍性考虑
  • 忽略移动端触摸事件

参考资料


版本: 1.0.0
兼容版本: @angular/cdk 20.x, Angular 20.3.x
最后更新: 2025-12-25