feat: 添加 useSafeNForm 组件及相关功能,更新依赖项,修复类型定义 [skip ci]
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router';
|
||||
import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
|
||||
import A2use from './utils/a2use.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -9,6 +10,8 @@ import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
|
||||
<Toast />
|
||||
|
||||
<AppNaiveUIProvider>
|
||||
<RouterView />
|
||||
<!-- <RouterView /> -->
|
||||
|
||||
<A2use></A2use>
|
||||
</AppNaiveUIProvider>
|
||||
</template>
|
||||
|
||||
112
src/utils/a2use.vue
Normal file
112
src/utils/a2use.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<script setup lang="ts">
|
||||
import { get, set } from 'lodash-es';
|
||||
|
||||
const { formValue, SafeNForm, SafeNFormItem, formRef } = useSafeNForm({
|
||||
initialFormValue: {
|
||||
/* ⚠️:
|
||||
如果没使用`SafeNFormItem`,
|
||||
这里`user`对象没有手动初始化的话,将会报错:
|
||||
`can't access property "name", $setup.formValue.user is undefined`
|
||||
*/
|
||||
user: {
|
||||
name: '',
|
||||
},
|
||||
phone: '',
|
||||
},
|
||||
});
|
||||
|
||||
function handleSetUserName() {
|
||||
set(formValue.value, 'user.name', 'Alice');
|
||||
}
|
||||
|
||||
function handleValidateClick_Safe_Form() {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
window.$nMessage!.success('Valid');
|
||||
} else {
|
||||
console.log(errors);
|
||||
window.$nMessage!.error('Invalid');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleValidateClick_Normal() {
|
||||
formRefNormal.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
window.$nMessage!.success('Valid');
|
||||
} else {
|
||||
console.log(errors);
|
||||
window.$nMessage!.error('Invalid');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const formRefNormal = useTemplateRef('formRefNormal');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div p-4>
|
||||
<div border>
|
||||
<div>formValue: {{ JSON.stringify(formValue) }}</div>
|
||||
<div>get(formValue, 'user.name'): {{ get(formValue, 'user.name') }}</div>
|
||||
</div>
|
||||
<n-space mt-4>
|
||||
<n-button @click="handleSetUserName">Set user.name</n-button>
|
||||
</n-space>
|
||||
|
||||
<n-space item-class="flex-1">
|
||||
<n-card title="SafeForm" mt-4>
|
||||
<SafeNForm>
|
||||
<n-form-item
|
||||
label="姓名"
|
||||
path="user.name"
|
||||
:rule="{ required: true, message: '请输入姓名', trigger: 'blur' }"
|
||||
>
|
||||
<n-input v-model:value="formValue.user.name" placeholder="输入姓名" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item
|
||||
label="电话号码"
|
||||
path="phone"
|
||||
:rule="{ required: true, message: '请输入电话号码', trigger: ['input'] }"
|
||||
>
|
||||
<n-input v-model:value="formValue.phone" placeholder="电话号码" />
|
||||
</n-form-item>
|
||||
|
||||
<SafeNFormItem #default="slotProps" path="phone">
|
||||
<div class="border">
|
||||
<pre>{{ JSON.stringify({ slotProps }, null, 2) }}</pre>
|
||||
</div>
|
||||
<!-- <NInput :value="value" placeholder="{props.placeholder}" /> -->
|
||||
</SafeNFormItem>
|
||||
|
||||
<n-form-item>
|
||||
<n-button attr-type="button" @click="handleValidateClick_Safe_Form"> 验证 </n-button>
|
||||
</n-form-item>
|
||||
</SafeNForm>
|
||||
</n-card>
|
||||
|
||||
<n-card title="普通 Form" mt-4>
|
||||
<n-form ref="formRefNormal" inline :model="formValue">
|
||||
<n-form-item
|
||||
label="姓名"
|
||||
path="user.name"
|
||||
:rule="{ required: true, message: '请输入姓名', trigger: 'blur' }"
|
||||
>
|
||||
<n-input v-model:value="formValue.user.name" placeholder="输入姓名" />
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="电话号码"
|
||||
path="phone"
|
||||
:rule="{ required: true, message: '请输入电话号码', trigger: ['input'] }"
|
||||
>
|
||||
<n-input v-model:value="formValue.phone" placeholder="电话号码" />
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<n-button attr-type="button" @click="handleValidateClick_Normal"> 验证 </n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</div>
|
||||
</template>
|
||||
94
src/utils/use-safe-n-form-auto-imports.tsx
Normal file
94
src/utils/use-safe-n-form-auto-imports.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
// https://www.naiveui.com/zh-CN/os-theme/components/form
|
||||
// initialFormValue
|
||||
|
||||
import { get } from 'lodash-es';
|
||||
import type { FormInst } from 'naive-ui';
|
||||
import type { Get, Paths } from 'type-fest';
|
||||
import type { SlotsType } from 'vue';
|
||||
|
||||
type UseSafeNFormOptions<T> = {
|
||||
initialFormValue?: T;
|
||||
};
|
||||
|
||||
export function useSafeNForm<T extends Record<string, any> = Record<string, unknown>>(
|
||||
options: UseSafeNFormOptions<T> = {},
|
||||
) {
|
||||
const formRef = ref<FormInst | null>(null);
|
||||
const formValue = ref<T>(structuredClone(toRaw(options.initialFormValue)) || ({} as T));
|
||||
|
||||
interface SafeNFormProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
type SafeNFormSlots = SlotsType<{
|
||||
default?: { count?: number };
|
||||
}>;
|
||||
|
||||
// 创建类型安全的 Form 组件
|
||||
const SafeNForm = defineComponent<SafeNFormProps, /* Emits */ [], /* EE */ never, SafeNFormSlots>(
|
||||
(props, ctx) => {
|
||||
return () => (
|
||||
<NForm
|
||||
inline={!true}
|
||||
label-width="auto"
|
||||
model={formValue.value}
|
||||
ref={(inst) => {
|
||||
formRef.value = inst as unknown as FormInst;
|
||||
}}
|
||||
>
|
||||
{ctx.slots.default?.({})}
|
||||
</NForm>
|
||||
);
|
||||
},
|
||||
{
|
||||
name: 'SafeNForm',
|
||||
inheritAttrs: false,
|
||||
props: ['disabled'],
|
||||
},
|
||||
);
|
||||
// <<<<<
|
||||
|
||||
// >>>>> 创建类型安全的 FormItem 组件
|
||||
interface SafeNFormItemProps {
|
||||
label?: string;
|
||||
path: Paths<T> /* & string */;
|
||||
placeholder?: string;
|
||||
}
|
||||
type SafeNFormItemSlots = SlotsType<{
|
||||
default: {
|
||||
value: Get<T, string>;
|
||||
};
|
||||
}>;
|
||||
|
||||
const SafeNFormItem = defineComponent<
|
||||
SafeNFormItemProps,
|
||||
/* Emits */ [],
|
||||
/* EE */ never,
|
||||
SafeNFormItemSlots
|
||||
>(
|
||||
(props, ctx) => {
|
||||
return () => {
|
||||
const value = get(formValue.value, props.path) as Get<T, string>;
|
||||
return (
|
||||
<NFormItem>
|
||||
{ctx.slots.default?.({
|
||||
value,
|
||||
})}
|
||||
</NFormItem>
|
||||
);
|
||||
};
|
||||
},
|
||||
{
|
||||
name: 'SafeNFormItem',
|
||||
inheritAttrs: false,
|
||||
props: ['label', 'path', 'placeholder'],
|
||||
},
|
||||
);
|
||||
// <<<<<
|
||||
|
||||
return {
|
||||
formValue,
|
||||
SafeNForm,
|
||||
SafeNFormItem,
|
||||
formRef,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user