Validator 验证器
轻量级内联验证包装器,用于单个表单元素的验证。与需要完整表单模型的 Form + FormItem 不同,PxValidator 可以包裹任意输入控件,当 Zod 验证失败时显示像素风格的提示文本。灵感来自 DaisyUI 的 Validator 模式。
| 名称 | 分类 | 说明 | 类型 |
|---|---|---|---|
rules | 行为 | 验证规则数组(支持 Zod schema 或 required 简写) | ValidatorRule[] |
modelValue | 内容 | 要验证的值 | unknown |
validate | 事件 | 验证完成后触发 | (isValid: boolean, message: string) => void |
default | 插槽 | 表单控件内容 | |
hint | 插槽 | 自定义错误提示内容 | { message: string } |
validate | 暴露 | 手动触发验证 | (trigger?: string) => Promise<boolean> |
reset | 暴露 | 重置验证状态 | () => void |
validateStatus | 暴露 | 当前验证状态 | Ref<'init' | 'error' | 'success'> |
validateMessage | 暴露 | 当前错误消息 | Ref<string> |
基础用法
用 PxValidator 包裹表单元素,绑定 v-model 并提供 rules。使用 required: true 作为非空字符串验证的简写。
<template>
<div class="demo-validator">
<px-validator v-model="name" :rules="rules">
<px-input v-model="name" placeholder="Enter your name" />
</px-validator>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const name = ref('');
const rules = [{ required: true, trigger: 'change' }];
</script>
<style scoped>
.demo-validator {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 320px;
}
</style>Zod Schema 验证
使用 Zod schema 进行丰富的验证 —— 邮箱格式、最小长度、正则匹配等。
<template>
<div class="demo-validator">
<px-validator v-model="email" :rules="emailRules">
<px-input v-model="email" placeholder="Email address" />
</px-validator>
<px-validator v-model="password" :rules="passwordRules">
<px-input v-model="password" type="password" placeholder="Password (min 6 chars)" />
</px-validator>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { z } from 'zod';
const email = ref('');
const password = ref('');
const emailRules = [{ schema: z.string().email('Please enter a valid email'), trigger: 'change' }];
const passwordRules = [
{ schema: z.string().min(6, 'Password must be at least 6 characters'), trigger: 'change' },
];
</script>
<style scoped>
.demo-validator {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 320px;
}
</style>自定义错误消息
在规则中使用自定义 message 覆盖 Zod 的默认错误提示。
<template>
<div class="demo-validator">
<px-validator v-model="age" :rules="rules">
<px-input v-model="age" placeholder="Enter your age" />
</px-validator>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { z } from 'zod';
const age = ref('');
const rules = [
{
schema: z.string().regex(/^\d+$/).pipe(z.coerce.number().min(1).max(150)),
message: 'Please enter a valid age (1-150)',
trigger: 'change',
},
];
</script>
<style scoped>
.demo-validator {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 320px;
}
</style>触发模式
使用 trigger 控制验证时机:'change'、'blur' 或 'input'。
<template>
<div class="demo-validator">
<p class="demo-validator__label">Validates on change:</p>
<px-validator v-model="val1" :rules="[{ required: true, trigger: 'change' }]">
<px-input v-model="val1" placeholder="Type and clear..." />
</px-validator>
<p class="demo-validator__label">Validates on blur:</p>
<px-validator v-model="val2" :rules="[{ required: true, trigger: 'blur' }]">
<px-input v-model="val2" placeholder="Focus and leave empty..." />
</px-validator>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const val1 = ref('');
const val2 = ref('');
</script>
<style scoped>
.demo-validator {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 320px;
}
.demo-validator__label {
font-family: var(--px-font-family);
font-size: 14px;
color: var(--px-text-color-secondary);
margin: 0;
}
</style>编程式验证
通过模板 ref 访问 validate() 和 reset() 进行手动控制。
<template>
<div class="demo-validator">
<px-validator ref="validatorRef" v-model="username" :rules="rules">
<px-input v-model="username" placeholder="Username" />
</px-validator>
<div class="demo-validator__actions">
<px-button type="primary" @click="handleValidate">Validate</px-button>
<px-button @click="handleReset">Reset</px-button>
</div>
<p class="demo-validator__result">
Status: {{ validatorRef?.validateStatus ?? 'init' }}
</p>
</div>
</template>
<script setup lang="ts">
import type { ValidatorInstance } from 'sakana-element';
import { ref } from 'vue';
import { z } from 'zod';
const username = ref('');
const validatorRef = ref<ValidatorInstance>();
const rules = [{ schema: z.string().min(3, 'Username must be at least 3 characters') }];
const handleValidate = async () => {
try {
await validatorRef.value?.validate();
} catch {
// validation failed
}
};
const handleReset = () => {
validatorRef.value?.reset();
};
</script>
<style scoped>
.demo-validator {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 320px;
}
.demo-validator__actions {
display: flex;
gap: 8px;
}
.demo-validator__result {
font-family: var(--px-font-family);
font-size: 14px;
color: var(--px-text-color-secondary);
margin: 0;
}
</style>