Flutter功能验证插件valida的使用

发布于 1周前 作者 caililin 来自 Flutter

Flutter功能验证插件valida的使用

valida 是一个用于Dart和Flutter的验证库,允许通过代码注解创建字段、参数和对象的验证器。以下是关于如何使用 valida 插件的完整示例demo。

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 valida 和相关生成器的依赖:

dependencies:
    valida: ^0.0.1

dev_dependencies:
    build_runner: <latest>
    valida_generator: ^0.0.1

然后运行 pub get 来安装依赖:

dart pub get

2. 创建模型类

接下来,创建一个模型类并使用 valida 注解来定义验证规则。以下是一个示例模型类 FormTest

import 'package:valida/valida.dart';

part 'model.g.dart';

@Valida(nullableErrorLists: true, customValidate: FormTest._customValidate)
class FormTest {
  static List<ValidaError> _customValidate(Object? value) {
    return [];
  }

  @ValidaString(
    minLength: 15,
    maxLength: 50,
    matches: r'^[a-zA-Z]+$',
    customValidate: _customValidateStr,
    description: '应包含15到50个字符,仅限字母且不能是 "WrongValue"',
  )
  final String longStr;

  @ValidaString(maxLength: 20, contains: '@')
  final String shortStr;

  @ValidaNum(isInt: true, min: 0, customValidate: _customValidateNum)
  final num positiveInt;

  static List<ValidaError> _customValidateNum(num value) {
    return [];
  }

  @ValidaFunction()
  static List<ValidaError> _customValidate2(FormTest value) {
    return [
      if (value.optionalDecimal == null && value.identifier == null)
        ValidaError(
          errorCode: 'CustomError.not',
          message: '自定义错误消息',
          property: 'identifier',
          value: value,
        )
    ];
  }

  @ValidaFunction()
  List<ValidaError> _customValidate3() {
    return _customValidate2(this);
  }

  @ValidaNum(
    min: 0,
    max: 1,
    comp: ValidaComparison<num>(
      less: CompVal(0),
      moreEq: CompVal.list([CompVal.ref('positiveInt')]),
    ),
  )
  final double? optionalDecimal;

  @ValidaList(minLength: 1, each: ValidaString(isDate: true, maxLength: 3))
  final List<String> nonEmptyList;

  @ValidaString(isUUID: UUIDVersion.v4)
  final String? identifier;

  final NestedField? nested;

  const FormTest({
    required this.longStr,
    required this.shortStr,
    required this.positiveInt,
    required this.optionalDecimal,
    required this.nonEmptyList,
    required this.identifier,
    this.nested,
  });
}

List<ValidaError> _customValidateStr(String value) {
  // 验证 `value` 并返回错误列表
  return [
    if (value == 'WrongValue')
      ValidaError(
        errorCode: 'CustomError.wrong',
        message: '不允许使用 "WrongValue"',
        property: 'longStr',
        value: value,
      ),
  ];
}

@Valida()
class NestedField {
  @ValidaString(isTime: true)
  final String timeStr;

  @ValidaDate(min: '2021-01-01')
  final DateTime dateWith2021Min;

  @ValidaDate(max: 'now')
  final DateTime? optionalDateWithNowMax;

  NestedField({
    required this.timeStr,
    required this.dateWith2021Min,
    required this.optionalDateWithNowMax,
  });
}

3. 生成验证代码

使用 build_runner 来生成验证代码:

dart pub run build_runner watch --delete-conflicting-outputs

这将生成一个名为 model.g.dart 的文件,其中包含验证逻辑。

4. 使用生成的验证函数

main.dart 中使用生成的验证函数 validateFormTest 来验证 FormTest 对象:

import 'model.dart';

void main() {
  const form = FormTest(
    longStr: 'long Str',
    shortStr: 'shortStr',
    positiveInt: 2.4,
    optionalDecimal: 3,
    nonEmptyList: [],
    identifier: 'identifier',
  );

  final FormTestValidation validation = validateFormTest(form);
  assert(validation is Validation<FormTest, FormTestField>);
  print('Number of errors: ${validation.numErrors}');
  print('Has errors: ${validation.hasErrors}');

  final errorsMap = validation.errorsMap;
  print('Errors map: $errorsMap');

  // 检查具体字段的错误
  if (errorsMap.isNotEmpty) {
    errorsMap.forEach((field, errors) {
      print('Field: $field, Errors: ${errors.map((e) => e.message)}');
    });
  }
}

5. 生成的验证代码

build_runner 生成的验证代码会包括以下几个部分:

  • 一个函数 ModelValidation validateModel(Model),用于执行验证。
  • ModelValidation 类,继承自 Validation<Model, ModelField>,包含错误数量、验证值、是否成功等实用属性。
  • 一个枚举 ModelField,表示被验证类的字段。
  • 一个实用类 ModelValidationFields,包含每个字段的错误列表。

以下是生成的 FormTestValidation 类的部分代码:

enum FormTestField {
  longStr,
  shortStr,
  positiveInt,
  optionalDecimal,
  nonEmptyList,
  identifier,
  nested,
  global,
}

class FormTestValidationFields {
  const FormTestValidationFields(this.errorsMap);
  final Map<FormTestField, List<ValidaError>> errorsMap;

  NestedFieldValidation? get nested {
    final l = errorsMap[FormTestField.nested];
    return (l != null && l.isNotEmpty)
        ? l.first.nestedValidation as NestedFieldValidation?
        : null;
  }

  List<ValidaError>? get longStr => errorsMap[FormTestField.longStr];
  List<ValidaError>? get shortStr => errorsMap[FormTestField.shortStr];
  List<ValidaError>? get positiveInt => errorsMap[FormTestField.positiveInt];
  List<ValidaError>? get optionalDecimal =>
      errorsMap[FormTestField.optionalDecimal];
  List<ValidaError>? get nonEmptyList => errorsMap[FormTestField.nonEmptyList];
  List<ValidaError>? get identifier => errorsMap[FormTestField.identifier];
}

class FormTestValidation extends Validation<FormTest, FormTestField> {
  FormTestValidation(this.errorsMap, this.value, this.fields)
      : super(errorsMap);

  final Map<FormTestField, List<ValidaError>> errorsMap;

  final FormTest value;

  final FormTestValidationFields fields;
}

FormTestValidation validateFormTest(FormTest value) {
  final errors = <FormTestField, List<ValidaError>>{};

  final _nestedValidation = value.nested == null
      ? null
      : validateNestedField(value.nested!).toError(property: 'nested');
  errors[FormTestField.nested] = [
    if (_nestedValidation != null) _nestedValidation
  ];

  errors[FormTestField.global] = [
    ...FormTest._customValidate2(value),
    ...value._customValidate3()
  ];
  errors[FormTestField.longStr] = [
    ..._customValidateStr(value.longStr),
    if (value.longStr.length < 15)
      ValidaError(
        message: r'长度应至少为15',
        errorCode: 'ValidaString.minLength',
        property: 'longStr',
        validationParam: 15,
        value: value.longStr,
      ),
    if (value.longStr.length > 50)
      ValidaError(
        message: r'长度应不超过50',
        errorCode: 'ValidaString.maxLength',
        property: 'longStr',
        validationParam: 50,
        value: value.longStr,
      ),
    if (!RegExp(r"^[a-zA-Z]+$").hasMatch(value.longStr))
      ValidaError(
        message: r'应匹配 ^[a-zA-Z]+$',
        errorCode: 'ValidaString.matches',
        property: 'longStr',
        validationParam: RegExp(r"^[a-zA-Z]+$"),
        value: value.longStr,
      )
  ];
  // ...
  // 更多验证逻辑
  // ...
  errors[FormTestField.nonEmptyList] = [
    if (value.nonEmptyList.length < 1)
      ValidaError(
        message: r'长度应至少为1',
        errorCode: 'ValidaList.minLength',
        property: 'nonEmptyList',
        validationParam: 1,
        value: value.nonEmptyList,
      )
  ];
  errors.removeWhere((k, v) => v.isEmpty);

  return FormTestValidation(
    errors,
    value,
    FormTestValidationFields(errors),
  );
}

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

1 回复

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


在Flutter开发中,validator 通常是用于表单验证的一种机制,而不是一个特定的插件名称。不过,假设你提到的 valida 是一个用于表单验证的Flutter插件(注意:实际中并不存在一个广泛认知的名为 valida 的Flutter插件,这里我将以一个假设的表单验证插件为例进行说明),我们可以模拟一个类似的表单验证插件的使用方式。

为了演示表单验证,我将使用Flutter的内置功能结合一些假设的验证逻辑来展示如何实现表单验证。在实际应用中,你可能需要使用一个具体的第三方验证插件,但原理是相似的。

示例代码

以下是一个简单的Flutter应用示例,它演示了如何使用自定义验证逻辑来验证表单输入:

import 'package:flutter/material.dart';

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

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

class MyFormPage extends StatefulWidget {
  @override
  _MyFormPageState createState() => _MyFormPageState();
}

class _MyFormPageState extends State<MyFormPage> {
  final _formKey = GlobalKey<FormState>();
  String _name = '';
  String _email = '';
  String _password = '';

  // 自定义验证函数
  String? validateName(String? value) {
    if (value == null || value.isEmpty) {
      return 'Name is required';
    }
    return null;
  }

  String? validateEmail(String? value) {
    if (value == null || !value.contains('@')) {
      return 'Please enter a valid email address';
    }
    return null;
  }

  String? validatePassword(String? value) {
    if (value == null || value.length < 6) {
      return 'Password must be at least 6 characters long';
    }
    return null;
  }

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      // 如果所有字段都通过验证
      _formKey.currentState!.save();
      print('Name: $_name');
      print('Email: $_email');
      print('Password: $_password');
      // 这里可以添加提交表单的逻辑,比如发送数据到服务器
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Form Validation Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(labelText: 'Name'),
                validator: validateName,
                onSaved: (value) => _name = value!,
              ),
              TextFormField(
                decoration: InputDecoration(labelText: 'Email'),
                validator: validateEmail,
                onSaved: (value) => _email = value!,
              ),
              TextFormField(
                decoration: InputDecoration(labelText: 'Password'),
                obscureText: true,
                validator: validatePassword,
                onSaved: (value) => _password = value!,
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _submitForm,
                child: Text('Submit'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

解释

  1. GlobalKey<FormState>:用于访问Form的状态,以便在提交时验证表单。
  2. TextFormField:用于创建文本输入字段,每个字段都有一个validator函数,该函数在表单提交时被调用。
  3. validator函数:每个验证函数都接受一个可能的空字符串值,并返回一个错误消息(如果输入无效)或null(如果输入有效)。
  4. onSaved回调:当表单验证通过并且用户提交表单时,这些回调用于保存字段的值。
  5. _submitForm方法:首先调用_formKey.currentState!.validate()来验证所有字段,如果验证通过,则调用_formKey.currentState!.save()来保存字段值,并执行提交逻辑。

这个例子展示了如何使用Flutter的内置功能来实现表单验证,而不是依赖于特定的第三方插件。如果你确实需要使用一个特定的验证插件(假设名为valida),你应该查阅该插件的文档来了解如何集成和使用它。通常,第三方插件会提供更高级或更便捷的验证功能,但基本原理是相似的。

回到顶部