表单组件 基础版本
- 实现的就是通过配置json格式来动态的渲染表单
(最重要) 表单的数据结构
interfaces/chooseForm/type
ts
// 引入验证规则
import { type RuleItem } from './rules'
// 引入css style类型
import { type CSSProperties } from 'vue'
// 表单每一项的配置选项
export interface FormOptions {
// 表单显示的元素
// 表单项显示的元素
type:
| 'cascader'
| 'checkbox'
| 'checkbox-group'
| 'checkbox-button'
| 'color-picker'
| 'date-picker'
| 'input'
| 'input-number'
| 'radio'
| 'radio-group'
| 'radio-button'
| 'rate'
| 'select'
| 'option'
| 'slider'
| 'switch'
| 'time-picker'
| 'time-select'
| 'transfer'
| 'upload'
| 'editor'
// 表单项的值
value: any
// 表单的表示
prop: string
// 表单项的label
label?: string
// 表单项的验证规则
rules?: RuleItem[]
// 表单项的占位符
placeholder?: string
// 表单元素特有的属性
attrs?: {
// css样式
style?: CSSProperties
clearable?: boolean
showPassword?: boolean
disabled?: boolean
}
}
interfaces/chooseForm/rules
- 这个rules 就是验证规则
ts
/*
* @Author: jsopy
* @Date: 2025-02-02 07:05:39
* @LastEditTime: 2025-02-02 07:05:45
* @FilePath: /zujian/src/interfaces/chooseForm/rules.ts
* @Description: 验证规则
*
*/
export type RuleType =
| 'string'
| 'number'
| 'boolean'
| 'method'
| 'regexp'
| 'integer'
| 'float'
| 'array'
| 'object'
| 'enum'
| 'date'
| 'url'
| 'hex'
| 'email'
| 'pattern'
| 'any'
export interface ValidateOption {
// whether to suppress internal warning
suppressWarning?: boolean
// when the first validation rule generates an error stop processed
first?: boolean
// when the first validation rule of the specified field generates an error stop the field processed, 'true' means all fields.
firstFields?: boolean | string[]
messages?: Partial<ValidateMessages>
/** The name of rules need to be trigger. Will validate all rules if leave empty */
keys?: string[]
error?: (rule: InternalRuleItem, message: string) => ValidateError
}
export type SyncErrorType = Error | string
export type SyncValidateResult = boolean | SyncErrorType | SyncErrorType[]
export type ValidateResult = void | Promise<void> | SyncValidateResult
export interface RuleItem {
type?: RuleType // default type is 'string'
required?: boolean
pattern?: RegExp | string
min?: number // Range of type 'string' and 'array'
max?: number // Range of type 'string' and 'array'
len?: number // Length of type 'string' and 'array'
enum?: Array<string | number | boolean | null | undefined> // possible values of type 'enum'
whitespace?: boolean
trigger?: string | string[]
fields?: Record<string, Rule> // ignore when without required
options?: ValidateOption
defaultField?: Rule // 'object' or 'array' containing validation rules
transform?: (value: Value) => Value
message?: string | ((a?: string) => string)
asyncValidator?: (
rule: InternalRuleItem,
value: Value,
callback: (error?: string | Error) => void,
source: Values,
options: ValidateOption
) => void | Promise<void>
validator?: (
rule: InternalRuleItem,
value: Value,
callback: (error?: string | Error) => void,
source: Values,
options: ValidateOption
) => SyncValidateResult | void
}
export type Rule = RuleItem | RuleItem[]
export type Rules = Record<string, Rule>
/**
* Rule for validating a value exists in an enumerable list.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param source The source object being validated.
* @param errors An array of errors that this rule may add
* validation errors to.
* @param options The validation options.
* @param options.messages The validation messages.
* @param type Rule type
*/
export type ExecuteRule = (
rule: InternalRuleItem,
value: Value,
source: Values,
errors: string[],
options: ValidateOption,
type?: string
) => void
/**
* Performs validation for any type.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
export type ExecuteValidator = (
rule: InternalRuleItem,
value: Value,
callback: (error?: string[]) => void,
source: Values,
options: ValidateOption
) => void
// >>>>> Message
type ValidateMessage<T extends any[] = unknown[]> = string | ((...args: T) => string)
type FullField = string | undefined
type EnumString = string | undefined
type Pattern = string | RegExp | undefined
type Range = number | undefined
type Type = string | undefined
export interface ValidateMessages {
default?: ValidateMessage
required?: ValidateMessage<[FullField]>
enum?: ValidateMessage<[FullField, EnumString]>
whitespace?: ValidateMessage<[FullField]>
date?: {
format?: ValidateMessage
parse?: ValidateMessage
invalid?: ValidateMessage
}
types?: {
string?: ValidateMessage<[FullField, Type]>
method?: ValidateMessage<[FullField, Type]>
array?: ValidateMessage<[FullField, Type]>
object?: ValidateMessage<[FullField, Type]>
number?: ValidateMessage<[FullField, Type]>
date?: ValidateMessage<[FullField, Type]>
boolean?: ValidateMessage<[FullField, Type]>
integer?: ValidateMessage<[FullField, Type]>
float?: ValidateMessage<[FullField, Type]>
regexp?: ValidateMessage<[FullField, Type]>
email?: ValidateMessage<[FullField, Type]>
url?: ValidateMessage<[FullField, Type]>
hex?: ValidateMessage<[FullField, Type]>
}
string?: {
len?: ValidateMessage<[FullField, Range]>
min?: ValidateMessage<[FullField, Range]>
max?: ValidateMessage<[FullField, Range]>
range?: ValidateMessage<[FullField, Range, Range]>
}
number?: {
len?: ValidateMessage<[FullField, Range]>
min?: ValidateMessage<[FullField, Range]>
max?: ValidateMessage<[FullField, Range]>
range?: ValidateMessage<[FullField, Range, Range]>
}
array?: {
len?: ValidateMessage<[FullField, Range]>
min?: ValidateMessage<[FullField, Range]>
max?: ValidateMessage<[FullField, Range]>
range?: ValidateMessage<[FullField, Range, Range]>
}
pattern?: {
mismatch?: ValidateMessage<[FullField, Value, Pattern]>
}
}
export interface InternalValidateMessages extends ValidateMessages {
clone: () => InternalValidateMessages
}
// >>>>> Values
export type Value = any
export type Values = Record<string, Value>
// >>>>> Validate
export interface ValidateError {
message?: string
fieldValue?: Value
field?: string
}
export type ValidateFieldsError = Record<string, ValidateError[]>
export type ValidateCallback = (errors: ValidateError[] | null, fields: ValidateFieldsError | Values) => void
export interface RuleValuePackage {
rule: InternalRuleItem
value: Value
source: Values
field: string
}
export interface InternalRuleItem extends Omit<RuleItem, 'validator'> {
field?: string
fullField?: string
fullFields?: string[]
validator?: RuleItem['validator'] | ExecuteValidator
}
自己封装的表单组件
- components/chooseForm/index.vue
vue
<template>
<!--改变后不需要立即验证-->
<el-form v-bind="$attrs" :model="model" :rules="rules" :validate-on-rule-change="false">
<el-form-item :prop="item.prop" v-for="(item, index) in options" :key="index" :label="item.label">
<component :is="`el-${item.type}`" v-bind="item.attrs" v-model="model[item.prop!]"></component>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { type PropType, ref, onMounted } from 'vue'
import { type FormOptions } from '@/interfaces/chooseForm/type'
let props = defineProps({
options: {
type: Array as PropType<FormOptions[]>,
required: true
}
})
// 最后的结果应该就是 {username: '', password: ''}
// rules: { username: [{ required: true, message: '请输入用户名', trigger: 'blur' }] }
let model = ref<any>({})
let rules = ref<any>({})
// 赋值数据属性和验证规则
let setRulesAndValue = () => {
let m: any = {}
let r: any = {}
props.options.map((item: FormOptions) => {
m[item.prop!] = item.value
r[item.prop!] = item.rules
})
model.value = JSON.parse(JSON.stringify(m))
rules.value = JSON.parse(JSON.stringify(r))
console.log(model.value)
console.log(rules.value)
}
onMounted(() => {
setRulesAndValue()
})
</script>
<style scoped></style>
父元素调用
vue
<template>
<div>
<YJ-choose-form :options="options" label-width="120px"></YJ-choose-form>
</div>
</template>
<script setup lang="ts">
import { type FormOptions } from '@/interfaces/chooseForm/type'
let options: FormOptions[] = [
{
type: 'input',
value: '',
label: '用户名',
prop: 'username',
attrs: {
clearable: true
}
},
{
type: 'input',
value: '',
label: '密码',
prop: 'password',
rules: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 15, message: '密码在6-15位之间', trigger: 'blur' }
],
attrs: {
showPassword: true,
clearable: true
}
}
]
</script>
<style scoped></style>