高级:拓展、覆盖组件
本示例展示如何在 ProForm 中拓展自定义组件并覆盖内置组件类型提示,对应 /antdv-next-pro/components/pro-form/#高级-typescript-类型推导与覆盖 的进阶用法。
关键思路
- 运行时:使用
ProComponentProvider注册componentMap,让component: 'text'能正确渲染。 - 类型提示:通过 声明合并 扩展
ComponentMap,让字段component自动获得类型推导。 - 覆盖提示:在
ComponentMap中重写input,即可替换默认组件的 Props 类型提示。 - 全局默认:通过
componentVars设置text的modelProp默认值。
表单展示
高级:拓展、覆盖组件
代码实现
vue
<script lang="ts" setup>
import { Card } from 'antdv-next';
import { ProComponentProvider, ProForm, useForm } from '@qin-ui/antdv-next-pro';
import CustomInput from '../custom-component/CustomInput.vue';
import TextDisplay from './TextDisplay.vue';
type FormData = {
name: string;
description: string;
};
const form = useForm<FormData>(
{ name: '', description: '很长很长的一段描述' },
[
{
label: '输入框(覆盖 input)',
path: 'name',
component: 'input',
extra: '这里会渲染 CustomInput',
},
{
label: '文本(拓展自定义组件 text)',
path: 'description',
component: 'text',
extra: '这里会渲染 TextDisplay',
},
]
);
const componentMap = {
text: TextDisplay,
input: CustomInput,
};
const componentVars = {
text: {
modelProp: 'content',
},
};
</script>
<template>
<ProComponentProvider
:component-map="componentMap"
:component-vars="componentVars"
>
<Card title="高级:拓展、覆盖组件">
<ProForm :form="form" />
</Card>
</ProComponentProvider>
</template>TextDisplay 代码实现
vue
<script lang="ts" setup>
defineProps<{ content?: string; placeholder?: string }>();
</script>
<template>
<span class="text-display">
{{ content || placeholder || '自定义 text 组件(modelProp=content)' }}
</span>
</template>
<style scoped>
.text-display {
color: #666;
}
</style>CustomInput 代码实现
vue
<script lang="ts" setup>
const value = defineModel<string>('value', { default: '' });
</script>
<template>
<!-- From Uiverse.io by ErzenXz -->
<input
type="text"
class="input"
v-bind="$attrs"
:value="value"
@input="e => (value = (e.target as any)?.value)"
/>
</template>
<style scoped lang="css">
/* From Uiverse.io by ErzenXz */
.input {
width: 100%;
height: 45px;
padding: 12px;
border: 1.5px solid lightgrey;
border-radius: 12px;
outline: none;
box-shadow: 0px 0px 20px -18px;
transition: all 0.3s cubic-bezier(0.19, 1, 0.22, 1);
}
.input:hover {
border: 2px solid lightgrey;
box-shadow: 0px 0px 20px -17px;
}
.input:active {
transform: scale(0.95);
}
.input:focus {
border: 2px solid grey;
}
</style>类型声明示例
ts
import 'antdv-next-pro';
import type TextDisplay from './TextDisplay.vue';
import type CustomInput from '../custom-component/CustomInput.vue';
declare module 'antdv-next-pro' {
interface ComponentMap {
text: typeof TextDisplay;
input: typeof CustomInput;
}
}