华为云的DevUI&Form组件实战:个人信息编辑表单完整实现

最近在做项目时用到了华为云的 DevUI 组件库,其中 Form 表单组件用得比较多。踩了不少坑,也总结了一些经验,分享给大家。

前言

表单是 Web 开发中最常见的交互组件,几乎每个后台管理系统都离不开它。我在使用 DevUI 的 Form 组件时,发现它的文档虽然全面,但实际项目中会遇到一些细节问题。这篇文章就是基于一个真实的个人信息编辑表单案例,讲讲怎么用 DevUI Form 组件,以及一些容易踩的坑。

一、项目环境准备

首先,确保你的项目已经安装了 ng-devui。如果还没装,可以看我上一篇的文章:
华为云 DevUI初体验:如何快速入门项目搭建

二、组件导入和基础结构

DevUI 的 Form 组件是基于 Angular Reactive Forms 的,所以需要导入 ReactiveFormsModule。看下我的组件导入:

typescript 复制代码
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { FormModule } from 'ng-devui/form';
import { TextInputModule } from 'ng-devui/text-input';
import { SelectModule } from 'ng-devui/select';
import { DatepickerModule } from 'ng-devui/datepicker';
import { RadioModule } from 'ng-devui/radio';
import { TextareaModule } from 'ng-devui/textarea';
import { ButtonModule } from 'ng-devui/button';

@Component({
  selector: 'app-form',
  standalone: true,
  imports: [
    CommonModule,
    ReactiveFormsModule,
    FormModule,
    TextInputModule,
    SelectModule,
    DatepickerModule,
    RadioModule,
    TextareaModule,
    ButtonModule
  ],
  templateUrl: './form.component.html',
  styleUrl: './form.component.scss'
})
export class FormComponent implements OnInit {
  // ...
}

注意几个点:

  • FormModule 提供了 dFormd-form-itemd-form-control 等核心组件
  • 各种输入组件需要单独导入对应的模块
  • 如果用的是 Angular 18 的 standalone 模式,记得把所有用到的模块都加到 imports 数组里

三、表单数据结构设计

我的表单包含基本信息、联系方式、工作信息和其他信息四个部分,总共 10 个字段。数据结构这样设计:

typescript 复制代码
userForm!: FormGroup;

// 性别选项
genderOptions = [
  { value: 'male', label: '男' },
  { value: 'female', label: '女' }
];

// 部门选项(注意:Select 组件需要 key-value 格式)
departmentOptions = [
  { key: 'tech', value: '技术部' },
  { key: 'product', value: '产品部' },
  { key: 'design', value: '设计部' },
  { key: 'operation', value: '运营部' },
  { key: 'hr', value: '人事部' }
];

// 城市选项
cityOptions = [
  { key: 'beijing', value: '北京' },
  { key: 'shanghai', value: '上海' },
  { key: 'guangzhou', value: '广州' },
  { key: 'shenzhen', value: '深圳' },
  { key: 'hangzhou', value: '杭州' }
];

这里有个坑:d-select 组件的 options 属性需要的是 { key, value } 格式,不是 { id, name } 或者 { value, label }。我一开始用错了格式,下拉框显示不出来,调试了半天才发现。

四、表单初始化和验证

表单初始化用 FormBuilder 来创建,验证规则直接在定义时加上:

typescript 复制代码
initForm(): void {
  this.userForm = this.fb.group({
    name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(20)]],
    age: [null, [Validators.required, Validators.min(18), Validators.max(100)]],
    gender: ['', Validators.required],
    birthday: [null, Validators.required],
    email: ['', [Validators.required, Validators.email]],
    phone: ['', [Validators.required, Validators.pattern(/^1[3-9]\d{9}$/)]],
    department: ['', Validators.required],
    city: ['', Validators.required],
    address: ['', [Validators.required, Validators.maxLength(200)]],
    description: ['', Validators.maxLength(500)]
  });
}

手机号验证用了正则表达式 /^1[3-9]\d{9}$/,只允许 1 开头、第二位是 3-9 的 11 位数字。年龄限制在 18-100 岁之间,这个根据业务需求调整。

五、模板结构

HTML 模板的结构比较清晰,用 dForm 指令包裹整个表单,每个字段用 d-form-item 包裹:

html 复制代码
<form dForm [formGroup]="userForm" (ngSubmit)="onSubmit()">
  <div class="form-section">
    <h3 class="section-title">基本信息</h3>
    
    <div class="form-row">
      <d-form-item class="form-item" [dHasFeedback]="true">
        <d-form-label>姓名 <span class="required-mark">*</span></d-form-label>
        <d-form-control>
          <input
            dTextInput
            formControlName="name"
            placeholder="请输入姓名"
          />
          <div class="error-message" *ngIf="isFieldInvalid('name')">
            {{ getFieldError("name") }}
          </div>
        </d-form-control>
      </d-form-item>
      <!-- 其他字段... -->
    </div>
  </div>
</form>

几个注意点:

  • dForm 指令必须加在 <form> 标签上
  • [dHasFeedback]="true" 用来显示验证反馈,注意是属性绑定,不能写成 dHasFeedback="true"
  • 错误提示用 *ngIf 控制显示,只在字段被触摸过且有错误时显示

六、常见问题处理

1. Textarea 组件的使用

d-textarea 其实是个指令,不是组件。应该这样用:

html 复制代码
<!-- 错误写法 -->
<d-textarea [rows]="4"></d-textarea>

<!-- 正确写法 -->
<textarea dTextarea [rows]="4"></textarea>

我一开始写成了组件形式,编译报错说找不到 rows 属性,后来查文档才发现是用法不对。

2. Select 组件的选项格式

d-selectoptions 属性需要特定格式:

typescript 复制代码
// 正确格式
departmentOptions = [
  { key: 'tech', value: '技术部' }
];

// 错误格式(这样不会显示)
departmentOptions = [
  { id: 'tech', name: '技术部' }
];

3. 表单验证错误提示

错误提示需要自己实现,DevUI 不会自动显示。我的做法是写两个辅助方法:

typescript 复制代码
// 检查字段是否有错误
isFieldInvalid(fieldName: string): boolean {
  const control = this.userForm.get(fieldName);
  return !!(control && control.invalid && control.touched);
}

// 获取字段错误信息
getFieldError(fieldName: string): string {
  const control = this.userForm.get(fieldName);
  if (control && control.touched && control.errors) {
    if (control.errors['required']) {
      return `${this.getFieldLabel(fieldName)}不能为空`;
    }
    if (control.errors['email']) {
      return '请输入有效的邮箱地址';
    }
    // ... 其他验证规则
  }
  return '';
}

这样可以在模板里统一处理错误提示,代码更清晰。

七、表单提交和重置

提交时先检查表单是否有效,无效的话把所有字段标记为 touched,这样错误提示就会显示出来:

typescript 复制代码
onSubmit(): void {
  if (this.userForm.valid) {
    console.log('表单数据:', this.userForm.value);
    // 这里可以调用 API 保存数据
    alert('保存成功!');
  } else {
    // 标记所有字段为 touched,显示验证错误
    Object.keys(this.userForm.controls).forEach(key => {
      this.userForm.get(key)?.markAsTouched();
    });
    alert('请检查表单输入是否正确!');
  }
}

重置功能比较简单,调用 reset() 方法就行。如果需要恢复默认值,可以在重置后重新 patchValue

八、样式优化

表单的样式可以根据项目需求自定义。我用了分组布局,每个分组有标题,字段用两列网格布局,移动端自动变成单列:

scss 复制代码
.form-section {
  margin-bottom: 32px;
  
  .section-title {
    font-size: 16px;
    font-weight: 600;
    margin: 0 0 20px 0;
    padding-bottom: 12px;
    border-bottom: 1px solid #e5e5e5;
  }
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  
  @media (max-width: 768px) {
    grid-template-columns: 1fr;
  }
}

总结

DevUI 的 Form 组件功能挺完善的,但用的时候要注意几个点:

  1. 组件导入要完整,特别是 standalone 模式下
  2. Select 组件的选项格式要用 { key, value }
  3. Textarea 是指令不是组件
  4. 验证错误提示需要自己实现
  5. dHasFeedback 要用属性绑定,不能用字符串

总的来说,DevUI Form 组件上手不难,但细节上容易踩坑。希望这篇文章能帮到正在使用 DevUI 的开发者。如果遇到其他问题,可以看看官方文档,或者去社区问问。

参考资源:

相关推荐
zhangwenwu的前端小站2 小时前
VUE 实现划词 问AI 翻译等功能
前端·javascript·vue.js
程序员小寒2 小时前
前端高频面试题之手写Promise
前端·javascript·面试
粉末的沉淀2 小时前
tauri:tauri2.0+vue3+vite打包案例
前端
丫丫7237342 小时前
Raycaster(鼠标点击选中模型)
javascript·webgl
北慕阳2 小时前
选择采购单按钮
前端·javascript·数据库
华仔啊2 小时前
Vite 到底能干嘛?为什么 Vue3 官方推荐它做工程化工具?
前端·javascript·vue.js
悟能不能悟2 小时前
目前流行的前端框架
开发语言·javascript·ecmascript
ZXH01222 小时前
性能提升60%:性能优化指南
前端·性能优化
赵庆明老师2 小时前
NET 中深度拷贝一个对象
前端·javascript·ui