Flutter表单验证插件ez_validator_dart的使用

Flutter表单验证插件ez_validator_dart的使用

Ez Validator

EzValidator提供了针对Flutter应用的简单易用的字段和对象模式验证方法。它受到Yup直观API的启发,简化了在Flutter应用程序中定义和实施数据模式的过程。

关键特性

  • Flutter Schema Builder: 无缝集成到你的Flutter项目中,构建和管理数据验证模式。
  • 灵活的验证: 无论是验证单个字段还是整个对象,EzValidator都能轻松应对。

安装

pubspec.yaml文件中添加EzValidator依赖:

dependencies:
  ez_validator_dart: any # 或者使用最新的版本

入门指南

开始使用EzValidator,首先定义一个表示数据结构和验证规则的模式对象。以下是一个示例,展示了如何为用户数据创建一个模式,包括对电子邮件、密码和日期字段的验证。

定义模式

使用EzSchema.shape创建模式,在数据对象的每个字段上关联一个EzValidator来指定其验证规则:

final EzSchema userSchema = EzSchema.shape(
  {
    "email": EzValidator<String>(label: "Email").required().email(),
    "password": EzValidator<String>(label: 'Password').required().minLength(8),
    'date': EzValidator<DateTime>()
        .required()
        .date()
        .minDate(DateTime(2019))
        .maxDate(DateTime(2025)),
  },
);

验证数据

使用模式的catchErrors方法来验证数据对象。该方法返回一个包含验证错误的映射(如果有):

final errors = userSchema.catchErrors({
  'email': 'example@domain.com',
  'password': '12345678',
  'date': DateTime.now(),
});

print(errors);

理解输出

  • 如果有验证错误,errors将包含一个字段名到错误消息的映射。例如:
{
  "password": "Minimum six characters, at least one letter, one number and one special character",
  "age": "The field must be greater than or equal to 18"
}
  • 如果数据对象符合模式,则errors将是一个空映射({})。

此外,可以使用validateSync方法同时验证数据并获取处理后的数据以及任何错误:

final (data, errors) = userSchema.validateSync({
  'email': 'example@domain.com',
  'password': '12345678',
  'date': DateTime.now(),
});

print(data);   // 处理后的数据
print(errors); // 验证错误

理解输出

  • 如果有验证错误,errors映射将包含字段名及其相应的错误消息。
  • 如果数据对象通过所有验证,errors将是一个空映射({})。
  • validateSync方法返回的data映射包含处理后的数据,可能包括由模式设置的默认值。

自定义验证

EzValidator还通过addMethod函数支持自定义验证规则。此功能允许你定义自己的验证逻辑,使EzValidator能够适应各种独特的使用场景。

使用addMethod进行自定义验证

你可以使用addMethod向验证器添加自定义验证函数。每个函数应该接受要验证的值作为参数,并在值通过验证时返回null,或在验证失败时返回错误消息。

以下是使用addMethod验证JSON结构的一个示例:

final checkJson = EzValidator<Map<String, dynamic>>()
    .addMethod((v) => v?['foo'] == 'bar' ? null : 'Foo should be bar')
    .addMethod((v) => v?['bar'] == 'Flutter' ? null : 'Bar should be Flutter')
    .addMethod((v) => v?['items'][0] == 'a' ? null : 'First item should be a')
    .build();

final errors = checkJson({
  'foo': 'bar',
  'bar': 'Flutter',
  'items': ['a', 'b', 'c']
});

print(errors); // 输出验证错误,如果有的话

如果这些检查中的任何一个失败,对应的错误消息将被返回。

自定义验证的灵活性

addMethod函数为自定义验证逻辑打开了无尽的可能性,使EzValidator能够根据特定的验证需求进行调整。

在Flutter小部件中直接使用

EzValidator设计得与Flutter小部件无缝集成,提供了一种简便的方式来为用户输入添加验证。常见的用例是在表单中,可以直接在表单字段如TextFormField中使用EzValidator

示例:在TextFormField中进行电子邮件验证

这是一个如何在TextFormField中应用EzValidator进行电子邮件验证的例子:

TextFormField(
  validator: EzValidator<String>()
      .required()
      .email()
      .build(),
  decoration: InputDecoration(labelText: 'Email'),
),

如果输入不符合这些验证条件,相应的错误消息将在TextFormField下方显示。

验证方法

EzValidator提供了广泛的方法来满足不同数据类型和验证场景的需求。以下是这些方法的概述:

通用验证

  • .required([String? message]): 确保值不为空。这是检查值存在的基本验证。
  • .isType(Type type, [String? message]): 验证值是否匹配指定的type
  • .minLength(int minLength, [String? message]): 检查值(字符串、列表或映射)的长度不小于指定的minLength
  • .maxLength(int maxLength, [String? message]): 确保值(字符串、列表或映射)的长度不超过指定的maxLength
  • .addMethod(bool Function(T? v) validWhen, [String? message]): 允许添加自定义验证逻辑。如果提供的validWhen函数返回false,则返回自定义错误消息。
  • .when(String key, ValidationCallback<T> validator): 基于模式中另一个字段的值提供条件验证。该方法接受一个key,引用模式中的另一个字段,以及一个执行验证逻辑的validator函数。如果验证通过,validator函数应返回null;否则返回自定义错误消息。
  • .transform(T Function(T) transformFunction): 在执行任何验证之前应用转换函数到字段的值。该方法接受一个transformFunction,接收当前字段值并返回转换后的值。

字符串验证

  • .email([String? message]): 验证值是否为有效的电子邮件地址。
  • .phone([String? message]): 验证值是否为有效的电话号码。
  • .ip([String? message]): 验证值是否为正确的IPv4地址。
  • .ipv6([String? message]): 验证值是否为正确的IPv6地址。
  • .url([String? message]): 验证值是否为有效的URL地址。
  • .uuid([String? message]): 验证值是否为有效的UUID。
  • .lowerCase([String? message]): 检查值是否为小写。
  • .upperCase([String? message]): 检查值是否为大写。
  • .matches(RegExp reg, [String? message]): 验证值是否匹配提供的正则表达式模式。

数字验证

  • .min(num min, [String? message]): 验证数值是否大于或等于min
  • .max(num max, [String? message]): 验证数值是否小于或等于max
  • .positive([String? message]): 验证数值是否为正数。
  • .negative([String? message]): 验证数值是否为负数。
  • .number([String? message]): 检查值是否为数字。
  • .isInt([String? message]): 检查值是否为整数。
  • .isDouble([String? message]): 检查值是否为双精度浮点数。
  • .notNumber([String? message]): 检查值是否不是数字。

日期验证

  • .date([String? message]): 检查值是否为有效日期。如果值为DateTime对象或可以解析为DateTime,则验证通过。
  • .minDate(DateTime date, [String? message]): 确保日期值不早于指定的最小日期。如果值为DateTime对象且等于或晚于提供的date,则验证通过。
  • .maxDate(DateTime date, [String? message]): 确保日期值不晚于指定的最大日期。如果值为DateTime对象且等于或早于提供的date,则验证通过。

布尔验证

  • .boolean([String? message]): 验证值是否为布尔值(truefalse)。该方法检查值的数据类型并确保它是严格的布尔值。

列表验证

  • .listOf(Type type, [String? message]): 验证列表中的每个元素是否为指定的type
  • .oneOf(List<T> items, [String? message]): 检查值是否为列表中的指定项之一。
  • .notOneOf(List<T> items, [String? message]): 确保值不是列表中的指定项之一。

使用自定义区域设置

EzValidator允许集成自定义区域设置,方便错误消息的本地化。以下是如何创建一个阿拉伯语区域设置(ArLocale)并在EzValidator中应用它的示例。

创建ArLocale

定义自定义区域设置:实现EzLocale接口以创建具有阿拉伯语错误消息的ArLocale

class ArLocale implements EzLocale {
  const ArLocale();

  // 实现所有必需的方法,带有阿拉伯语错误消息
  @override
  String minLength(String v, int n, [String? label]) =>
      '${label ?? 'الحقل'} يجب أن يحتوي على الأقل $n أحرف';
  // ... 其他方法实现 ...

  @override
  String required([String? label]) => '${label ?? 'الحقل'} مطلوب';

  // 示例实现有效的电子邮件
  @override
  String email(String v, [String? label]) =>
      '${label ?? 'الحقل'} ليس بريدًا إلكترونيًا صحيحًا';

  // ... 更多其他方法的实现 ...
}

EzValidator中设置区域设置:配置EzValidator以使用ArLocale

EzValidator.setLocale(const ArLocale());

像平常一样使用验证器:现在,验证错误消息将是阿拉伯语。

使用EzValidator进行嵌套验证示例

EzValidator不仅处理简单的验证,还擅长管理复杂的嵌套数据结构。这对于处理复杂的多层数据模型特别有用,比如具有多个细节层次的用户配置文件。以下是使用EzValidator定义嵌套验证模式的一个例子:

定义复杂用户配置文件模式

final EzSchema userProfileSchema = EzSchema.shape({
  "firstName": EzValidator<String>().required(),
  "lastName": EzValidator<String>().required(),
  "email": EzValidator<String>().required().email(),
  "age": EzValidator<int>().min(18).max(100),
  'contactDetails': EzSchema.shape({
    'mobile': EzValidator<String>()
        .required()
        .matches(RegExp(r'^\+\d{10,15}$'), 'Invalid phone number'),
    'landline': EzValidator<String?>(optional: true),
  }),
  'address': EzSchema.shape({
    'street': EzValidator<String>().required(),
    'city': EzValidator<String>().required(),
    'state': EzValidator<String>().required(),
    'zipCode': EzValidator<num>().required(),
    'country': EzSchema.shape({
      'name': EzValidator<String>(defaultValue: 'TUNISIA').required(),
      'code': EzValidator<String>().required(),
      'continent': EzSchema.shape({
        'name': EzValidator<String>().required(),
        'code': EzValidator<String>().required(),
      })
    }),
  }),
  'employment': EzSchema.shape({
    'current': EzValidator<String?>(optional: true),
    'previous': EzSchema.shape({
      'companyName': EzValidator<String>().required(),
      'position': EzValidator<String>().required(),
      'years': EzValidator<int>().min(1).max(50),
    }),
  }),
});

验证

final (data, errors) = userProfileSchema.validateSync({
  'firstName': 'John',
  'lastName': 'Doe',
  'email': 'john.doe@example.com',
  'age': 30,
  'contactDetails': {
    'mobile': '+12345678901',
  },
  'address': {
    'street': '123 Main St',
    'city': 'Anytown',
    'state': 'Anystate',
    'zipCode': 12345,
    'country': { }, // 我不会定义国家
  },
  'employment': {
    'current': 'Current Company',
    'previous': {
      'companyName': 'Previous Company',
      'position': 'Previous Position',
      'years': 5,
    },
  },
});

print(data);

// 显示的数据结果将包含具有默认值的国家
// {
//   firstName: John,
//   lastName: Doe,
//   email: john.doe@example.com,
//   age: 30,
//   contactDetails: { mobile: +12345678901, landline: null },
//   address:
//     {
//       street: 123 Main St,
//       city: Anytown,
//       state: Anystate,
//       zipCode: 12345,
//       country:
//         { name: TUNISIA, code: null, continent: { name: null, code: null } },
//     },
//   employment:
//     {
//       current: Current Company,
//       previous:
//         {
//           companyName: Previous Company,
//           position: Previous Position,
//           years: 5,
//         },
//     },
// }
//

print(errors);

// {address: {country: {code: The field is required, continent: {name: The field is required, code: The field is required}}}}

使用.when.transform方法的示例

此示例演示了如何在EzValidator中使用.when.transform方法进行条件验证和预验证数据转换。

final EzSchema schema = EzSchema.shape({
  // 使用.transform在验证名称前修剪空白
  "name": EzValidator<String>()
      .transform((value) => value.trim())
      .minLength(3, "Name must be at least 3 characters long."),

  // 使用.when基于密码字段验证confirmPassword
  "password": EzValidator<String>()
      .minLength(8, "Password must be at least 8 characters long."),
  "confirmPassword": EzValidator<String>().when(
    "password",
    (confirmValue, [ref]) =>
        confirmValue == ref?["password"] ? null : "Passwords do not match",
  )
});

var result = schema.validateSync({
  "name": "  John  ",
  "password": "password123",
  "confirmPassword": "password123",
});

print(result); // 如果没有验证错误,应该为空

更多关于Flutter表单验证插件ez_validator_dart的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter表单验证插件ez_validator_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用ez_validator_dart插件进行表单验证的代码示例。ez_validator_dart是一个简单且强大的表单验证库,它允许你轻松地定义和验证表单字段。

首先,确保你已经在pubspec.yaml文件中添加了ez_validator_dart依赖:

dependencies:
  flutter:
    sdk: flutter
  ez_validator_dart: ^最新版本号  # 请替换为当前最新版本号

然后,运行flutter pub get来安装依赖。

接下来,让我们创建一个简单的Flutter应用,演示如何使用ez_validator_dart进行表单验证。

import 'package:flutter/material.dart';
import 'package:ez_validator_dart/ez_validator_dart.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  late final EzValidator _validator;

  @override
  void initState() {
    super.initState();

    _validator = EzValidator([
      EzField(
        name: 'email',
        rules: [
          EzRequiredRule(),
          EzEmailRule(),
        ],
      ),
      EzField(
        name: 'password',
        rules: [
          EzRequiredRule(),
          EzMinLengthRule(6),
        ],
      ),
    ]);
  }

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  void _submitForm() async {
    if (_formKey.currentState!.validate()) {
      final Map<String, String> formData = {
        'email': _emailController.text,
        'password': _passwordController.text,
      };

      final Map<String, List<String>> errors = await _validator.validateMap(formData);

      if (errors.isEmpty) {
        // 表单验证通过,执行提交操作
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('表单提交成功!')),
        );
      } else {
        // 显示错误信息
        errors.forEach((key, value) {
          value.forEach((error) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text("$key: $error")),
            );
          });
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('表单验证示例'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: <Widget>[
              TextFormField(
                controller: _emailController,
                decoration: InputDecoration(labelText: 'Email'),
                validator: (value) {
                  // 使用内置的Flutter验证器进行初步验证
                  if (value == null || value.isEmpty) {
                    return 'Email不能为空';
                  } else if (!_validator.validateField('email', value)) {
                    return '无效的Email地址';
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: _passwordController,
                decoration: InputDecoration(labelText: 'Password'),
                obscureText: true,
                validator: (value) {
                  // 使用内置的Flutter验证器进行初步验证
                  if (value == null || value.isEmpty) {
                    return '密码不能为空';
                  } else if (value.length < 6) {
                    return '密码长度至少为6个字符';
                  } else if (!_validator.validateField('password', value)) {
                    return '密码不符合要求';
                  }
                  return null;
                },
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _submitForm,
                child: Text('提交'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,包含两个文本字段(Email和密码)和一个提交按钮。我们使用ez_validator_dart来定义和验证这些字段的规则。在提交表单时,我们首先使用Flutter内置的验证器进行初步验证,然后调用_validator.validateMap方法进行进一步的验证。如果验证通过,显示一个成功的消息;否则,显示相应的错误信息。

请注意,这个示例结合了Flutter内置的表单验证和ez_validator_dart插件的功能,以便在提交表单之前捕获并显示错误。

回到顶部