Appearance
自定义 type
d-render 允许你注册自定义组件类型,扩展框架能力。
自定义 type 的本质
自定义 type = 向 DRender 注册一个新的组件映射。
最简示例
1. 创建组件配置文件
js
// src/components/custom-input/component-config.js
export default {
myInput: {
component: (mode) => () => import(`./my-input${mode}`)
}
}2. 在 d-render.config.js 中注册
js
import customInputsPlugin from '@/components/custom-input/component-config'
export default {
plugins: [
customInputsPlugin
]
}3. 使用自定义类型
js
const fieldList = generateFieldList({
username: {
type: 'myInput',
label: '用户名'
}
})注册配置详解
基本格式
js
{
[typeName]: {
component: (mode) => () => import(`./path/to/component${mode}`)
}
}多模式支持
组件可以注册多个渲染模式:
- 默认模式:
/index - 只读模式:
/view - 移动端模式:
/mobile - 配置模式:
/configure
js
{
mySelect: {
component: (mode) => () => import(`./my-select${mode}`)
}
}目录结构:
my-select/
├── index.vue # 默认模式
├── view.vue # 只读模式
├── mobile.vue # 移动端模式
└── configure.vue # 配置模式如果某个模式不存在,会 fallback 到默认组件。
布局类型
如果是布局组件,需要标记 layout: true:
js
{
myLayout: {
component: (mode) => () => import(`./my-layout${mode}`),
layout: true
}
}自定义组件开发指南
使用 useFormInput hook(推荐)
vue
<template>
<el-input
v-model="proxyValue"
:placeholder="config.placeholder"
:disabled="config.disabled"
/>
</template>
<script setup>
import { useFormInput, formInputProps, formInputEmits } from '@d-render/shared'
const props = defineProps(formInputProps)
const emit = defineEmits(formInputEmits)
const { proxyValue, proxyOtherValue, width } = useFormInput(props, emit, {
maxOtherKey: 2
})
</script>useFormInput 提供的能力
proxyValue- 主字段值的响应式代理proxyOtherValue- otherKey 值的响应式代理数组width- 字段宽度securityConfig- 安全的配置对象
组件 props
使用 formInputProps 会自动包含:
modelValue- 主值otherValue- 附加值config- 字段配置对象dependOnValues- 依赖值对象outDependOnValues- 外部依赖值对象
组件 emits
使用 formInputEmits 会自动包含:
update:modelValue- 更新主值update:otherValue- 更新附加值
支持联动
响应依赖变化
vue
<script setup>
import { watch } from 'vue'
import { useFormInput, formInputProps, formInputEmits } from '@d-render/shared'
const props = defineProps(formInputProps)
const emit = defineEmits(formInputEmits)
const { proxyValue, securityConfig } = useFormInput(props, emit)
// 监听依赖变化
watch(() => props.dependOnValues, (values) => {
if (securityConfig.value.autoFill && values.province) {
proxyValue.value = getDefaultCity(values.province)
}
}, { deep: true })
</script>提供异步选项
vue
<script setup>
import { ref, watch } from 'vue'
import { useFormInput, formInputProps, formInputEmits } from '@d-render/shared'
const props = defineProps(formInputProps)
const emit = defineEmits(formInputEmits)
const { proxyValue, securityConfig } = useFormInput(props, emit)
const options = ref([])
// 组件配置中声明 asyncOptions
const loadOptions = async () => {
if (securityConfig.value.asyncOptions) {
options.value = await securityConfig.value.asyncOptions(props.dependOnValues)
}
}
watch(() => props.dependOnValues, loadOptions, { immediate: true })
</script>支持 otherKey
单个 otherKey
vue
<script setup>
import { useFormInput, formInputProps, formInputEmits } from '@d-render/shared'
const props = defineProps(formInputProps)
const emit = defineEmits(formInputEmits)
const { proxyValue, proxyOtherValue } = useFormInput(props, emit, {
maxOtherKey: 1
})
const handleChange = (value, label) => {
proxyValue.value = value
proxyOtherValue[0].value = label
}
</script>多个 otherKey
vue
<script setup>
import { useFormInput, formInputProps, formInputEmits } from '@d-render/shared'
const props = defineProps(formInputProps)
const emit = defineEmits(formInputEmits)
const { proxyValue, proxyOtherValue } = useFormInput(props, emit, {
maxOtherKey: 3
})
const handleChange = (value, label, option, path) => {
proxyValue.value = value
proxyOtherValue[0].value = label
proxyOtherValue[1].value = option
proxyOtherValue[2].value = path
}
</script>完整示例:带搜索的选择器
vue
<template>
<el-select
v-model="proxyValue"
filterable
remote
:remote-method="handleSearch"
:loading="loading"
:placeholder="config.placeholder"
:disabled="config.disabled"
@change="handleChange"
>
<el-option
v-for="item in options"
:key="item[valueKey]"
:label="item[labelKey]"
:value="item[valueKey]"
/>
</el-select>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
import { useFormInput, formInputProps, formInputEmits } from '@d-render/shared'
const props = defineProps(formInputProps)
const emit = defineEmits(formInputEmits)
const { proxyValue, proxyOtherValue, securityConfig } = useFormInput(props, emit, {
maxOtherKey: 2
})
const loading = ref(false)
const options = ref([])
const valueKey = computed(() => securityConfig.value.valueKey || 'value')
const labelKey = computed(() => securityConfig.value.labelKey || 'label')
// 搜索方法
const handleSearch = async (query) => {
if (!query) {
options.value = []
return
}
loading.value = true
try {
if (securityConfig.value.remoteMethod) {
options.value = await securityConfig.value.remoteMethod(query)
}
} finally {
loading.value = false
}
}
// 选择时更新主值和 otherKey
const handleChange = (value) => {
const selected = options.value.find(item => item[valueKey.value] === value)
proxyOtherValue[0].value = selected?.[labelKey.value]
proxyOtherValue[1].value = selected
}
// 支持联动
watch(() => props.dependOnValues, () => {
proxyValue.value = undefined
proxyOtherValue[0].value = undefined
proxyOtherValue[1].value = undefined
options.value = []
}, { deep: true })
</script>注册配置:
js
export default {
searchSelect: {
component: (mode) => () => import(`./search-select${mode}`)
}
}使用:
js
{
userId: {
type: 'searchSelect',
label: '用户',
otherKey: ['userName', 'userOption'],
placeholder: '请输入关键词搜索',
valueKey: 'id',
labelKey: 'name',
remoteMethod: async (query) => {
const res = await searchUser(query)
return res.data
}
}
}配置模式组件
配置模式用于设计器中配置字段属性。
vue
<template>
<div class="my-input-configure">
<el-form-item label="占位文本">
<el-input v-model="config.placeholder" />
</el-form-item>
<el-form-item label="最大长度">
<el-input-number v-model="config.maxLength" />
</el-form-item>
</div>
</template>
<script setup>
defineProps({
config: Object
})
</script>最佳实践
1. 始终使用 useFormInput
避免自己处理复杂的值同步逻辑。
2. 明确 otherKey 顺序
在组件文档中清楚说明 otherKey 数组每个位置的含义。
3. 支持常用配置
至少支持:
placeholderdisabledreadonly
4. 处理联动
如果组件是选项类,支持:
dependOn触发重新加载asyncOptions异步获取选项
5. 提供配置模式
如果组件有特殊配置,提供 configure 模式。
6. 提供只读模式
view 模式用于详情展示。
7. 提供移动端模式
mobile 模式适配移动端 UI。
常见问题
Q: 组件加载失败?
A: 检查动态导入路径是否正确,确保文件存在。
Q: 配置不生效?
A: 确保在应用启动前调用 dRender.setConfig()。
Q: otherKey 不工作?
A: 检查是否正确使用了 useFormInput 并设置了 maxOtherKey。
Q: 如何支持验证?
A: 使用 d-render 内置的验证机制,在配置中设置 required、regexpValidate 等。