delon-utilSkill delon-util

@delon/util 是一个专为 Angular 应用设计的实用函数库,提供数组、字符串、日期、数字和浏览器操作的常用工具函数。核心功能包括深度复制(deepCopy)、深度合并(deepMerge)、字符串格式化、日期范围计算、货币格式化、剪贴板操作等。适用于前端开发、数据操作、状态管理、表单处理等场景,帮助开发者提高代码复用性和开发效率。关键词:Angular工具库、前端开发、数据操作、实用函数、deepCopy、deepMerge、字符串格式化、日期处理、浏览器API、状态管理、不可变性、TypeScript、ng-alain、组件开发。

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

name: delon-util description: ‘@delon/util 技能 - 用于数组、字符串、日期、数字操作的实用函数库。适用于 ng-events 建筑工地进度跟踪系统。’

@delon/util - 实用函数库

触发模式:“utility”, “helper”, “@delon/util”, “format”, “deepCopy”, “deepMerge”

概述

@delon/util 为 ng-alain 应用程序中的常见数据操作任务提供了一套全面的实用函数集合。

: @delon/util@20.1.0

分类

1. 数组实用工具 (array/)

deepCopy - 深度复制数组/对象

import { deepCopy } from '@delon/util/array';

const original = { name: '任务', items: [1, 2, 3], meta: { id: 1 } };
const copy = deepCopy(original);

// 对副本的更改不会影响原始对象
copy.items.push(4);
console.log(original.items); // [1, 2, 3]
console.log(copy.items);     // [1, 2, 3, 4]

使用场景:

  • 为不可变性克隆状态对象
  • 在修改前创建独立副本
  • 深度克隆表单数据

deepMerge - 深度合并对象

import { deepMerge } from '@delon/util/array';

const defaults = {
  config: { theme: 'light', size: 'default' },
  features: ['dashboard']
};

const custom = {
  config: { theme: 'dark' },
  features: ['reports']
};

const merged = deepMerge(defaults, custom);
// 结果: {
//   config: { theme: 'dark', size: 'default' },
//   features: ['dashboard', 'reports']
// }

其他数组函数

import { 
  groupBy,     // 按属性分组数组
  uniq,        // 去重
  uniqBy,      // 按属性去重
  orderBy      // 按属性排序数组
} from '@delon/util/array';

// 按状态分组任务
const grouped = groupBy(tasks, 'status');
// { pending: [...], completed: [...] }

// 移除重复的ID
const uniqueIds = uniq([1, 2, 2, 3]); // [1, 2, 3]

// 按ID移除重复任务
const uniqueTasks = uniqBy(tasks, 'id');

// 排序任务
const sorted = orderBy(tasks, ['priority', 'createdAt'], ['asc', 'desc']);

2. 字符串实用工具 (string/)

format - 字符串格式化

import { format } from '@delon/util/string';

// 模板插值
const message = format('任务 {0} 已指派给 {1}', taskName, userName);

// 命名参数
const message2 = format('任务 {name} 的状态为 {status}', { 
  name: '地基施工', 
  status: '进行中' 
});

其他字符串函数

import { 
  toCamelCase,    // 转换为 camelCase
  toPascalCase,   // 转换为 PascalCase
  toKebabCase,    // 转换为 kebab-case
  toSnakeCase,    // 转换为 snake_case
  truncate        // 截断并添加省略号
} from '@delon/util/string';

toCamelCase('task-name');     // 'taskName'
toPascalCase('task-name');    // 'TaskName'
toKebabCase('TaskName');      // 'task-name'
toSnakeCase('TaskName');      // 'task_name'
truncate('Long text...', 10); // 'Long te...'

3. 日期实用工具 (date/)

getTimeDistance - 获取时间范围

import { getTimeDistance } from '@delon/util/date';

// 获取今天的日期范围
const today = getTimeDistance('today');
// [Date(2024-12-25 00:00:00), Date(2024-12-25 23:59:59)]

// 获取本周的日期范围
const week = getTimeDistance('week');

// 获取本月的日期范围
const month = getTimeDistance('month');

// 获取本年的日期范围
const year = getTimeDistance('year');

// 带偏移量的自定义范围
const lastWeek = getTimeDistance('week', -1);

支持的类型:

  • 'today' - 当前天
  • 'week' - 当前周(周日至周六)
  • 'month' - 当前月
  • 'year' - 当前年
  • 自定义偏移量(负数为过去,正数为未来)

formatDistanceToNow - 相对时间

import { formatDistanceToNow } from '@delon/util/date';

const createdAt = new Date('2024-12-20');
const relative = formatDistanceToNow(createdAt);
// "5天前"

const futureDate = new Date('2024-12-30');
const future = formatDistanceToNow(futureDate);
// "5天后"

4. 数字实用工具 (number/)

currency - 货币格式化

import { currency } from '@delon/util/number';

// 格式化为货币
currency(1234567.89);              // "$1,234,567.89"
currency(1234567.89, { unit: '¥' }); // "¥1,234,567.89"
currency(1234.5, { precision: 0 });  // "$1,235"

其他数字函数

import { 
  toFixed,      // 四舍五入到固定小数位
  toPercent,    // 转换为百分比
  toThousands   // 添加千位分隔符
} from '@delon/util/number';

toFixed(1.2345, 2);           // "1.23"
toPercent(0.1234);            // "12.34%"
toPercent(0.1234, 1);         // "12.3%"
toThousands(1234567);         // "1,234,567"

5. 浏览器实用工具 (browser/)

copyToClipboard - 复制到剪贴板

import { copy } from '@delon/util/browser';

async copyTaskLink(taskId: string) {
  const link = `${window.location.origin}/tasks/${taskId}`;
  const success = await copy(link);
  
  if (success) {
    this.messageService.success('链接已复制');
  } else {
    this.messageService.error('复制失败');
  }
}

其他浏览器函数

import { 
  scrollToTop,    // 平滑滚动到顶部
  deepGet,        // 获取嵌套对象属性
  deepSet,        // 设置嵌套对象属性
  isEmpty,        // 检查值是否为空
  isEqual,        // 深度相等检查
  updateHostClass // 更新宿主元素类
} from '@delon/util/browser';

scrollToTop();
scrollToTop({ duration: 500 });

const value = deepGet(obj, 'user.profile.name');
deepSet(obj, 'user.profile.name', 'New Name');

isEmpty(null);      // true
isEmpty('');        // true
isEmpty([]);        // true
isEmpty({});        // true

isEqual({ a: 1 }, { a: 1 }); // true

实际应用示例

任务管理实用工具

import { Component, signal, computed, inject } from '@angular/core';
import { deepCopy, groupBy, orderBy } from '@delon/util/array';
import { format } from '@delon/util/string';
import { getTimeDistance } from '@delon/util/date';
import { copy } from '@delon/util/browser';
import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
  selector: 'app-task-list',
  standalone: true,
  template: `
    <nz-card>
      <div nz-row [nzGutter]="16">
        @for (group of groupedTasks() | keyvalue; track group.key) {
          <div nz-col [nzSpan]="8">
            <h3>{{ group.key }} ({{ group.value.length }})</h3>
            @for (task of group.value; track task.id) {
              <nz-card>
                <h4>{{ task.title }}</h4>
                <p>{{ formatTaskInfo(task) }}</p>
                <button nz-button (click)="copyTaskLink(task.id)">
                  复制链接
                </button>
              </nz-card>
            }
          </div>
        }
      </div>
    </nz-card>
  `
})
export class TaskListComponent {
  private messageService = inject(NzMessageService);
  
  // 来自服务的原始任务
  tasks = signal<Task[]>([]);
  
  // 使用 @delon/util 按状态分组任务
  groupedTasks = computed(() => 
    groupBy(this.sortedTasks(), 'status')
  );
  
  // 按优先级和日期排序任务
  sortedTasks = computed(() => 
    orderBy(
      this.tasks(),
      ['priority', 'createdAt'],
      ['asc', 'desc']
    )
  );
  
  // 格式化任务信息
  formatTaskInfo(task: Task): string {
    return format(
      '优先级: {priority}, 创建于 {date}',
      {
        priority: task.priority,
        date: this.formatDate(task.createdAt)
      }
    );
  }
  
  // 复制任务链接到剪贴板
  async copyTaskLink(taskId: string): Promise<void> {
    const link = `${window.location.origin}/tasks/${taskId}`;
    const success = await copy(link);
    
    if (success) {
      this.messageService.success('任务链接已复制');
    } else {
      this.messageService.error('复制失败,请手动复制');
    }
  }
  
  // 克隆任务用于编辑
  cloneTaskForEdit(task: Task): Task {
    return deepCopy(task);
  }
  
  // 获取本周的任务
  getThisWeekTasks(): Task[] {
    const [start, end] = getTimeDistance('week');
    return this.tasks().filter(t => 
      t.createdAt >= start && t.createdAt <= end
    );
  }
  
  private formatDate(date: Date): string {
    return format(
      '{year}-{month}-{day}',
      {
        year: date.getFullYear(),
        month: String(date.getMonth() + 1).padStart(2, '0'),
        day: String(date.getDate()).padStart(2, '0')
      }
    );
  }
}

表单数据实用工具

import { Component, signal } from '@angular/core';
import { deepCopy, deepMerge } from '@delon/util/array';
import { isEmpty } from '@delon/util/browser';

@Component({
  selector: 'app-task-form',
  standalone: true,
  template: `
    <form nz-form (ngSubmit)="handleSubmit()">
      <!-- 表单字段 -->
      <button nz-button [disabled]="hasEmptyRequired()">
        提交
      </button>
    </form>
  `
})
export class TaskFormComponent {
  // 默认表单值
  private defaults = {
    priority: 'medium',
    status: 'pending',
    assignee: null,
    tags: []
  };
  
  // 带默认值的表单数据
  formData = signal(deepCopy(this.defaults));
  
  // 原始任务(用于编辑)
  originalTask = signal<Task | null>(null);
  
  // 加载任务进行编辑
  loadTask(task: Task): void {
    // 合并任务数据与默认值
    const merged = deepMerge(this.defaults, task);
    this.formData.set(merged);
    this.originalTask.set(deepCopy(task));
  }
  
  // 检查必填字段是否为空
  hasEmptyRequired(): boolean {
    const data = this.formData();
    return isEmpty(data.title) || isEmpty(data.assignee);
  }
  
  // 检查表单是否有更改
  hasChanges(): boolean {
    const original = this.originalTask();
    if (!original) return true;
    
    return !isEqual(original, this.formData());
  }
  
  handleSubmit(): void {
    if (!this.hasEmptyRequired()) {
      // 为提交创建干净副本
      const submitData = deepCopy(this.formData());
      // 提交...
    }
  }
}

最佳实践

1. 使用实用工具实现不可变性

应该这样做:

const taskCopy = deepCopy(task);
taskCopy.status = 'completed';
this.tasks.update(tasks => [...tasks, taskCopy]);

不应该这样做:

task.status = 'completed';
this.tasks.update(tasks => [...tasks, task]); // 修改了原始对象

2. 结合实用工具使用计算信号

应该这样做:

groupedTasks = computed(() => groupBy(this.tasks(), 'status'));
sortedTasks = computed(() => orderBy(this.tasks(), ['priority'], ['asc']));

3. 使用类型安全的实用工具

应该这样做:

import { deepCopy } from '@delon/util/array';

const copy: Task = deepCopy<Task>(originalTask);

性能考虑

  1. deepCopy: 对于大型对象开销较大 - 谨慎使用
  2. groupBy/orderBy: 包装在 computed() 中以避免重复计算
  3. getTimeDistance: 如果频繁使用,缓存结果
  4. copy: 异步操作 - 处理加载状态

集成检查清单

  • [ ] 安装 @delon/util@20.1.0
  • [ ] 导入特定实用工具(支持 tree-shaking)
  • [ ] 与 Angular Signals 结合使用以实现响应性
  • [ ] 添加 TypeScript 泛型以确保类型安全
  • [ ] 处理异步操作(复制)
  • [ ] 测试边界情况(null、undefined、空值)

交叉参考

  • angular-component - 信号集成
  • delon-form - 表单验证实用工具
  • firebase-repository - 状态管理的 deepCopy

版本: 1.0
创建日期: 2025-12-25
维护者: ng-events(GigHub) 开发团队