refactor: 移除未使用的 RouterView 组件,优化 a2use 组件的模板和 SafeNFormItem 的实现
Some checks failed
CI/CD Pipeline / playwright (push) Successful in 3m25s
CI/CD Pipeline / build-and-deploy (push) Failing after 3m29s

This commit is contained in:
严浩
2025-10-31 12:53:59 +08:00
parent 18cb623730
commit 66419d22d4
3 changed files with 47 additions and 36 deletions

View File

@@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { RouterView } from 'vue-router';
import AppNaiveUIProvider from './AppNaiveUIProvider.vue'; import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
import A2use from './utils/a2use.vue'; import A2use from './utils/a2use.vue';
</script> </script>

View File

@@ -35,7 +35,9 @@ function handleValidateClick() {
<template> <template>
<div p-4> <div p-4>
<div border> <div border>
<div>formValue: {{ JSON.stringify(formValue) }}</div> <div>
<pre>formValue: {{ JSON.stringify(formValue, null, 2) }}</pre>
</div>
<div>get(formValue, 'user.name'): {{ get(formValue, 'user.name') }}</div> <div>get(formValue, 'user.name'): {{ get(formValue, 'user.name') }}</div>
</div> </div>
<n-space mt-4> <n-space mt-4>
@@ -44,7 +46,7 @@ function handleValidateClick() {
<n-space item-class="flex-1"> <n-space item-class="flex-1">
<n-card title="SafeForm" mt-4> <n-card title="SafeForm" mt-4>
<SafeNForm> <SafeNForm label-placement="left" label-width="auto">
<n-form-item <n-form-item
label="姓名" label="姓名"
path="user.name" path="user.name"
@@ -53,6 +55,15 @@ function handleValidateClick() {
<n-input v-model:value="formValue.user.name" placeholder="输入姓名" /> <n-input v-model:value="formValue.user.name" placeholder="输入姓名" />
</n-form-item> </n-form-item>
<SafeNFormItem
#default="{ value, setValue }"
:rule="{ required: true, message: '请输入姓名', trigger: ['input'] }"
label="姓名"
path="user.name"
>
<NInput :value="value" placeholder="SafeNFormItem" @update:value="setValue" />
</SafeNFormItem>
<n-form-item <n-form-item
label="电话号码" label="电话号码"
path="phone" path="phone"
@@ -61,14 +72,6 @@ function handleValidateClick() {
<n-input v-model:value="formValue.phone" placeholder="电话号码" /> <n-input v-model:value="formValue.phone" placeholder="电话号码" />
</n-form-item> </n-form-item>
<SafeNFormItem #default="slotProps" path="user.name">
<div class="border">
<!-- <pre>{{ JSON.stringify({ slotProps: toRaw(slotProps) }, null, 2) }}</pre> -->
<div>v: {{ slotProps.value }}</div>
</div>
<NInput v-model:value="slotProps.value" placeholder="SafeNFormItem" />
</SafeNFormItem>
<n-form-item> <n-form-item>
<n-button attr-type="button" @click="handleValidateClick"> 验证 </n-button> <n-button attr-type="button" @click="handleValidateClick"> 验证 </n-button>
</n-form-item> </n-form-item>

View File

@@ -1,13 +1,18 @@
// https://www.naiveui.com/zh-CN/os-theme/components/form /**
// initialFormValue * https://www.naiveui.com/zh-CN/os-theme/components/form
*
* FIXME: `NForm` 和 `NFormItem` 的 slots 还没有实现。`NFormItemGi`组件。
*/
import { get, set } from 'lodash-es'; import { get, set } from 'lodash-es';
import type { FormInst } from 'naive-ui'; import type { FormInst, FormItemProps, FormProps } from 'naive-ui';
import { NForm, NFormItem, formItemProps, NInput, formProps } from 'naive-ui';
import type { Get, Paths } from 'type-fest'; import type { Get, Paths } from 'type-fest';
import type { SlotsType } from 'vue'; import type { SlotsType } from 'vue';
import { Comment } from 'vue';
type UseSafeNFormOptions<T> = { type UseSafeNFormOptions<FormValue> = {
initialFormValue?: T; initialFormValue?: FormValue;
}; };
export function useSafeNForm<T extends Record<string, any> = Record<string, unknown>>( export function useSafeNForm<T extends Record<string, any> = Record<string, unknown>>(
@@ -17,9 +22,8 @@ export function useSafeNForm<T extends Record<string, any> = Record<string, unkn
const formValue = ref<T>(structuredClone(toRaw(options.initialFormValue)) || ({} as T)); const formValue = ref<T>(structuredClone(toRaw(options.initialFormValue)) || ({} as T));
// 创建类型安全的 Form 组件 // 创建类型安全的 Form 组件
interface SafeNFormProps { type SafeNFormProps = FormProps;
disabled?: boolean;
}
type SafeNFormSlots = SlotsType<{ type SafeNFormSlots = SlotsType<{
default?: { count?: number }; default?: { count?: number };
}>; }>;
@@ -28,8 +32,7 @@ export function useSafeNForm<T extends Record<string, any> = Record<string, unkn
(props, ctx) => { (props, ctx) => {
return () => ( return () => (
<NForm <NForm
inline={!true} {...props}
label-width="auto"
model={formValue.value} model={formValue.value}
ref={(inst) => { ref={(inst) => {
formRef.value = inst as unknown as FormInst; formRef.value = inst as unknown as FormInst;
@@ -42,20 +45,19 @@ export function useSafeNForm<T extends Record<string, any> = Record<string, unkn
{ {
name: 'SafeNForm', name: 'SafeNForm',
inheritAttrs: false, inheritAttrs: false,
props: ['disabled'], props: formProps,
}, },
); );
// <<<<< // <<<<<
// >>>>> 创建类型安全的 FormItem 组件 // >>>>> 创建类型安全的 FormItem 组件
type SafeNFormItemProps<P extends Paths<T> & string> = { type SafeNFormItemProps<P extends Paths<T> & string> = FormItemProps & {
label?: string;
path: P; path: P;
placeholder?: string;
}; };
type SafeNFormItemDefaultSlot<P extends Paths<T> & string> = { type SafeNFormItemDefaultSlot<P extends Paths<T> & string> = {
value: Get<T, P>; value: Get<T, P>;
setValue: (val: Get<T, P>) => void;
}; };
const SafeNFormItemImpl = defineComponent< const SafeNFormItemImpl = defineComponent<
@@ -66,18 +68,25 @@ export function useSafeNForm<T extends Record<string, any> = Record<string, unkn
>( >(
(props, ctx) => { (props, ctx) => {
return () => { return () => {
// const value = get(formValue.value, props.path) as Get<T, typeof props.path>; const value = get(formValue.value, props.path);
const value = computed({ function setValue(val: typeof value) {
get() { set(formValue.value, props.path, val);
return get(formValue.value, props.path) as Get<T, typeof props.path>; }
},
set(v) { const defaultSlotContent = ctx.slots.default?.({
set(formValue.value, props.path, v); value,
}, setValue,
}); });
// 如果没有提供默认 slot 内容,则渲染一个 NInput 作为默认输入组件
const renderDefaultNInput = defaultSlotContent?.some((v) => v.type !== Comment) ? null : (
<NInput value={value} onUpdate:value={setValue} />
);
return ( return (
<NFormItem path={props.path} label={props.label}> <NFormItem {...props} path={props.path}>
{ctx.slots.default?.({ value: value.value })} {defaultSlotContent}
{renderDefaultNInput}
</NFormItem> </NFormItem>
); );
}; };
@@ -85,7 +94,7 @@ export function useSafeNForm<T extends Record<string, any> = Record<string, unkn
{ {
name: 'SafeNFormItem', name: 'SafeNFormItem',
inheritAttrs: false, inheritAttrs: false,
props: ['label', 'path', 'placeholder'], props: Object.keys(formItemProps) as unknown as [keyof FormItemProps],
}, },
); );