vee-validate,yup,pinia的使用

337 阅读3分钟

vee-validate

useForm

useForm 是一个自定义组合 API 函数,允许您对 useField 创建的字段进行分组并聚合它们的状态。它应该用于创建逻辑表单或自定义表单组件,类似于 <Form/> 组件,它只是 useForm 的消费者。

import { useForm } from 'vee-validate';
const { errors, errorBag, isSubmitting, isValidating, meta, values, setErrors, setFieldError, setFieldValue, setValues, setFieldTouched, setTouched, validate, validateField, handleSubmit, submitForm, submitCount, resetForm, handleReset, defineField } = useForm({
    // 如果为true,则一旦装载了表单组件,它将触发对所有字段的验证。
    validateOnMount: true,
    // 启用表单级验证,使用指定的架构验证字段。架构可以是有效的 vee-validate 全局验证程序或函数,也可以是 yup 对象架构。
    validationSchema: {},
    // 表单的初始值可以是响应式对象或引用。
    initialValues: { email: '', password: '', },
    // 字段的初始错误对于Laravel等非水合SSR应用程序很有用,错误是在挂载时应用的。
    initialErrors: {},
    // 表单字段的初始触摸状态,应用于已装载。
    initialTouched: {},
});
// 一个将字段名映射到其错误消息的对象,如果存在多个字段,它只接受每个字段的第一个错误消息。
errors.value; // 访问错误值
// 一个将字段名称映射到其所有错误消息的对象。
errorBag.value.email; // 电子邮件字段错误
// 指示提交处理程序是否仍在运行,一旦它解决/拒绝,它将再次自动设置为 false。
isSubmitting.value; // true 或 false
// 指示 validate 函数是否仍在运行,一旦 validate 函数完成,它将再次自动设置为 `false`。
isValidating.value; // true 或 false
// 一个计算属性,其中包含一个聚合的元信息/标志,反映表单内所有字段的状态。
meta.value; // { valid: false, invalid: true, dirty: true, .... }
// 一个包含当前表单值的响应式属性,您不应该尝试直接对其进行修改。
values; // { email: 'something@gmail.com', .... }
// 设置多个字段错误消息,内部使用 `setFieldError`
setErrors({
    email: 'This field is invalid', // 设置对应值的错误信息
});
// 设置字段的值,如果字段不存在,则不会反映在`值(ref)` 中。这将触发对值已更改的字段的验证。
setFieldValue('email', 'example@gmail.com'); // 设置单个值
// 设置字段的错误消息,这对于设置来自 API 的消息或不可用作验证规则的消息非常有用。将消息设置为 `undefined` 或空字符串可清除错误并将字段标记为有效。
setFieldError('email', 'this email is already taken');
// 设置所有字段值,将触发对已更改字段的验证
setValues({ email: 'example@gmail.com', password: 'p@a$$W0rD',});
// 设置字段的 `touched` meta 标志,如果为不存在的字段设置它,则无效。
setFieldTouched('email', true);
// 设置多个字段 `touched` meta 标志,不验证.
setTouched({ email: true, password: false,});
// 验证所有字段并填充 `errors` 对象,返回一个 Promise,该 Promise 解析为包含所有字段的聚合验证结果的对象。
const { valid, errors } = await validate();
// 验证表单中的特定字段,返回一个 Promise,该 Promise 解析为包含验证结果的对象。
const { valid, errors } = await validateField('email');
// 这是一个用于创建`提交`事件处理程序的高阶函数,您不应该直接将其用作事件的处理程序,而应使用它来创建这些处理程序。
// 使用“onSubmit”作为表单的事件处理程序
const onSubmit = handleSubmit((values, actions) => {
    alert(JSON.stringify(values, null, 2));
    
    // 表单对象包含有用的方法
    // 设置单个字段值
    actions.setFieldValue('field', 'hello'); 
    // 设置多个字段值
    actions.setValues({ email: 'value', password: 'hi' }); 
    // 设置单个字段错误 
    actions.setFieldError('field', 'this field is bad'); 
    // 设置多个字段错误
    actions.setErrors({ email: 'bad email', password: 'bad password' }); 
    // 重置表单
    actions.resetForm();
    
    // `handleSubmit` 包含一个 `withControlled` 函数,您可以使用该函数仅提交由 `useField` 或 `useFieldModel` 控制的字段。
    const onSubmit = handleSubmit.withControlled(values => {
        // 仅向API发送受控值
        // 仅打印用“useField”或“useFieldModel”声明的字段
        alert(JSON.stringify(values, null, 2));});
    });
    // 用户尝试提交的次数,每当调用 `submitForm` 或 `handleSubmit` 回调时,它都会递增。
    submitCount
    // 清除错误消息,重置所有字段的元状态,并将其值恢复为初始状态以及 `submitCount` 状态。接受包含新表单状态的可选对象,如果您需要将表单值重置为初始状态以外的其他值,则这很有用。
    resetForm({
        values: {
            firstName: '',
            lastName: '',
            email: '',
            password: '',
        },
    });
    // 默认情况下,`resetForm` 会将之前的初始值与提供的新初始值合并,这意味着只有提供的初始值将被覆盖。您可以通过在第二个参数中传递 `force: true` 来覆盖所有字段。
    resetForm({
        values: { fname: 'test' }
    }, { force: true });
    // 清除错误消息,重置所有字段的元状态,并将其值恢复为初始状态以及 `submitCount` 状态。您可以将此函数用作本机表单元素上 `reset` 事件的处理程序。
    handleReset();

useFieldArray

useFieldArray 是一个自定义的组合 API 函数,允许您管理可重复的字段和表单条目,并提供常用操作帮助程序。

  • 可导出值
// 这是数组项的 *只读* 版本
fields: Ref<FieldEntry<TValue>[]>;
// 从数组中删除指定索引处的项(如果存在)。
remove(idx: number): void;
// 替换整个字段数组。
replace(newArray: TValue[]): void; 
// 更新指定索引处的值,请注意,如果值是对象,则不会合并这些值。如果指定的索引在数组边界之外,则操作将被忽略。
update(idx: number, value: TValue): void;
// 将项添加到数组的末尾
push(value: TValue): void; 
// 将给定索引中的项目相互交换。这两个索引都必须存在于数组中,否则不会产生影响。
swap(indexA: number, indexB: number): void; 
// 在指定索引处添加项目。如果指定的索引会将项目置于越界之外(即:大于 length),则该操作将被忽略,您仍然可以将项目添加为数组的最后一项。
insert(idx: number, value: TValue): void;
// 将项添加到数组的开头
prepend(value: TValue): void;
// 将数组项移动到数组中的其他位置。
move(oldIdx: number, newIdx: number): void;
  • 应用
import { useForm, useFieldArray } from 'vee-validate';
const { handleSubmit } = useForm({
        initialValues: {
            links: [{ id: 1, url: 'https://github.com/logaretm' }], 
        },
});
const { fields, remove, replace, update, push, swap, insert, prepend, move } = useFieldArray('links');
const onSubmit = handleSubmit(values => {
    console.log(JSON.stringify(values, null, 2));
});

yup

import { object, string, number, date, InferType } from 'yup';
let userSchema = object({
  name: string().required(),
  age: number().required().positive().integer(),
  email: string().email(),
  website: string().url().nullable(),
  createdOn: date().default(() => new Date()),
});

pinia

创建

import { defineStore } from 'pinia'

const useStore = defineStore('storeId', {
  // 推荐使用 完整类型推断的箭头函数
  state: () => {
    return {
      // 所有这些属性都将自动推断其类型
      counter: 0,
    }
  },
 getters: {
    doubleCount: (state) => state.counter * 2,
 },
 actions: {
    increment() {
      this.counter++
    }
 })

使用 setup()

import { useCounterStore } from '../stores/counterStore'

export default {
  setup() {
    const counterStore = useCounterStore()

    return { counterStore }
  },
  computed: {
    tripleCounter() {
      return counterStore.counter * 3
    },
  },
}

不使用 setup()

import { mapState, mapWritableState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'

export default {
  computed: {
  
    // 允许访问组件内部的 this.counter
    // 与从 store.counter 读取相同
    ...mapState(useCounterStore, {
      myOwnName: 'counter',
      // 您还可以编写一个访问 store 的函数
      double: store => store.counter * 2,
      // 它可以正常读取“this”,但无法正常写入...
      magicValue(store) {
        return store.someGetter + this.counter + this.double
      },
    }),
    
    
    
    // 允许访问组件内的 this.counter 并允许设置它
    // this.counter++
    // 与从 store.counter 读取相同
    ...mapWritableState(useCounterStore, ['counter'])
    // 与上面相同,但将其注册为 this.myOwnName
    ...mapWritableState(useCounterStore, {
      myOwnName: 'counter',
    }),
    
  },
}

使用 storeToRefs

import { useCounterStore } from '../stores/counterStore'
const store = useCounterStore();
// 通过构建新的 state 对象将 store 重置为其初始状态。
store.$reset();
// 创建一个引用对象,其中包含 store 的所有 state、getter 和插件添加的 state 属性。类似于 `toRefs(),`但专门为 Pinia 存储设计,因此方法和非响应式属性被完全忽略。
const stateGetter = storeToRefs(store);

改变状态

const store = useStore()
// 默认情况下,您可以通过 `store` 实例访问状态来直接读取和写入状态
store.counter++
// 调用 `$patch` 方法。 它允许您使用部分“state”对象同时应用多个更改
store.$patch({
  counter: store.counter + 1,
  name: 'Abalam',
})
// `$patch` 方法也接受一个函数来批量修改集合内部分对象的情况:
cartStore.$patch((state) => {
  state.items.push({ name: 'shoes', quantity: 1 })
  state.hasChanged = true
})

替换state

store.$state = { counter: 666, name: 'Paimon' }
pinia.state.value = {}

混合使用

  1. 新建一个文件xxxStore.ts 用于xx页面的表单操作
  2. 在xxx页面上导入

xxxStore.ts 其中 useForm 全局引入

import {
  array, object, string,
} from 'yup';

const usexxxStore = defineStore('xxxForm', {
  state: () => {
    const {
      validate,
      values: allValues,
      validateField,
      setFieldValue,
      resetForm,
    } = useForm({
      keepValuesOnUnmount: true,
      validationSchema: object({
        a: string().required().label('a名称'),
        bList: array()
          .of(
            object({
              c: string().required().label('c类型'),
            }),
          ),
      }),
      initialValues: {
        a: '',
        bList: [],
      },
    });

    const state = {
      a: '',
      bList: [],
    };


    return {
      validateField,
      validate,
      allValues,
      setFieldValue,
      resetForm,
      ...state,
    };
  },

  getters: {},
  actions: {},
});

export default usexxxStore;

xxx.vue 其中 useFieldArray 全局引入

<script setup>
import usexxxStore from '../xxxStore';
const store = useResourceApplyStore();
const { allValues } = storeToRefs(store);
const { remove, update } = useFieldArray('bList');
</script>