refactor: 优化 SafeNFormItem 组件的类型定义和插槽处理
This commit is contained in:
@@ -63,10 +63,10 @@ function handleValidateClick() {
|
||||
|
||||
<SafeNFormItem #default="slotProps" path="user.name">
|
||||
<div class="border">
|
||||
<pre>{{ JSON.stringify({ slotProps }, null, 2) }}</pre>
|
||||
<!-- <pre>{{ JSON.stringify({ slotProps: toRaw(slotProps) }, null, 2) }}</pre> -->
|
||||
<div>v: {{ slotProps.value }}</div>
|
||||
</div>
|
||||
<NInput :value="slotProps.value" placeholder="SafeNFormItem" />
|
||||
<NInput v-model:value="slotProps.value" placeholder="SafeNFormItem" />
|
||||
</SafeNFormItem>
|
||||
|
||||
<n-form-item>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// https://www.naiveui.com/zh-CN/os-theme/components/form
|
||||
// initialFormValue
|
||||
|
||||
import { get } from 'lodash-es';
|
||||
import { get, set } from 'lodash-es';
|
||||
import type { FormInst } from 'naive-ui';
|
||||
import type { Get, Paths } from 'type-fest';
|
||||
import type { SlotsType } from 'vue';
|
||||
@@ -48,45 +48,36 @@ export function useSafeNForm<T extends Record<string, any> = Record<string, unkn
|
||||
// <<<<<
|
||||
|
||||
// >>>>> 创建类型安全的 FormItem 组件
|
||||
|
||||
type SafeNFormItemProps<P extends Paths<T> & string> = {
|
||||
label?: string;
|
||||
path: P;
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
type SafeNFormItemSlotScope<P extends Paths<T> & string> = {
|
||||
type SafeNFormItemDefaultSlot<P extends Paths<T> & string> = {
|
||||
value: Get<T, P>;
|
||||
};
|
||||
|
||||
type SafeNFormItemSlotsDefinition<P extends Paths<T> & string> = SlotsType<{
|
||||
default: SafeNFormItemSlotScope<P>;
|
||||
}>;
|
||||
|
||||
type SafeNFormItemSlotFns<P extends Paths<T> & string> = {
|
||||
default?: (scope: SafeNFormItemSlotScope<P>) => any;
|
||||
};
|
||||
|
||||
type SafeNFormItemComponent = new <P extends Paths<T> & string>(
|
||||
props: SafeNFormItemProps<P>,
|
||||
) => {
|
||||
$props: SafeNFormItemProps<P>;
|
||||
$slots: SafeNFormItemSlotFns<P>;
|
||||
};
|
||||
|
||||
const SafeNFormItemImpl = defineComponent<
|
||||
SafeNFormItemProps<Paths<T> & string>,
|
||||
/* Emits */ [],
|
||||
/* EE */ never,
|
||||
SafeNFormItemSlotsDefinition<Paths<T> & string>
|
||||
SlotsType<{ default: SafeNFormItemDefaultSlot<Paths<T> & string> }>
|
||||
>(
|
||||
(props, ctx) => {
|
||||
return () => {
|
||||
const value = get(formValue.value, props.path) as Get<T, typeof props.path>;
|
||||
const slots = ctx.slots;
|
||||
// const value = get(formValue.value, props.path) as Get<T, typeof props.path>;
|
||||
const value = computed({
|
||||
get() {
|
||||
return get(formValue.value, props.path) as Get<T, typeof props.path>;
|
||||
},
|
||||
set(v) {
|
||||
set(formValue.value, props.path, v);
|
||||
},
|
||||
});
|
||||
return (
|
||||
<NFormItem path={props.path} label={props.label}>
|
||||
{slots.default?.({ value })}
|
||||
{ctx.slots.default?.({ value: value.value })}
|
||||
</NFormItem>
|
||||
);
|
||||
};
|
||||
@@ -97,7 +88,19 @@ export function useSafeNForm<T extends Record<string, any> = Record<string, unkn
|
||||
props: ['label', 'path', 'placeholder'],
|
||||
},
|
||||
);
|
||||
const SafeNFormItem = SafeNFormItemImpl as unknown as SafeNFormItemComponent;
|
||||
|
||||
// Expose a generic constructor so template literals narrow `path`.
|
||||
type SafeNFormItemComponent = {
|
||||
new <P extends Paths<T> & string>(
|
||||
props: SafeNFormItemProps<P>,
|
||||
): {
|
||||
$props: SafeNFormItemProps<P>;
|
||||
$slots: {
|
||||
default?: (scope: SafeNFormItemDefaultSlot<P>) => VNode[];
|
||||
};
|
||||
};
|
||||
};
|
||||
const SafeNFormItem = SafeNFormItemImpl as SafeNFormItemComponent;
|
||||
// <<<<<
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user