wip(VForm): VForm component development
This commit is contained in:
parent
69909e2832
commit
d9d64f3931
90
src/App.vue
90
src/App.vue
|
@ -39,6 +39,27 @@ onMounted(() => {
|
||||||
restaurants.value = loadAll()
|
restaurants.value = loadAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const initials = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
|
||||||
|
const options = ref<FormOptions[]>(
|
||||||
|
Array.from({ length: 1000 }).map((_, idx) => ({
|
||||||
|
value: `Option ${idx + 1}`,
|
||||||
|
label: `${initials[idx % 10]}${idx}`
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
const options2 = ref<FormOptions[]>(
|
||||||
|
Array.from({ length: 10 }).map((_, idx) => {
|
||||||
|
const label = idx + 1
|
||||||
|
return {
|
||||||
|
value: `Group ${label}`,
|
||||||
|
label: `Group ${label}`,
|
||||||
|
options: Array.from({ length: 10 }).map((_, idx) => ({
|
||||||
|
value: `Option ${idx + 1 + 10 * label}`,
|
||||||
|
label: `${initials[idx % 10]}${idx + 1 + 10 * label}`
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const schema = reactive<VFormSchema[]>([
|
const schema = reactive<VFormSchema[]>([
|
||||||
{
|
{
|
||||||
field: 'field1',
|
field: 'field1',
|
||||||
|
@ -238,6 +259,45 @@ const schema = reactive<VFormSchema[]>([
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
optionsSlot: true
|
optionsSlot: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field17',
|
||||||
|
label: `${t('formDemo.selectV2')}`,
|
||||||
|
component: 'Divider'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field18',
|
||||||
|
label: t('formDemo.default'),
|
||||||
|
component: 'SelectV2',
|
||||||
|
options: options.value
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field18',
|
||||||
|
label: t('formDemo.slot'),
|
||||||
|
component: 'SelectV2',
|
||||||
|
options: options.value,
|
||||||
|
componentProps: {
|
||||||
|
slots: {
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field19',
|
||||||
|
label: t('formDemo.group'),
|
||||||
|
component: 'SelectV2',
|
||||||
|
options: options2.value
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field20',
|
||||||
|
label: `${t('formDemo.group')}${t('formDemo.slot')}`,
|
||||||
|
component: 'SelectV2',
|
||||||
|
options: options2.value,
|
||||||
|
componentProps: {
|
||||||
|
slots: {
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
</script>
|
</script>
|
||||||
|
@ -260,18 +320,32 @@ const schema = reactive<VFormSchema[]>([
|
||||||
<span class="link">{{ item.link }}</span>
|
<span class="link">{{ item.link }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #field14-option="item">
|
<template #field14-option="{ item }">
|
||||||
<span style="float: left">{{ item.label }}</span>
|
<span style="float: left">{{ item.label }}</span>
|
||||||
<span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">{{
|
<span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
|
||||||
item.value
|
{{ item.value }}
|
||||||
}}</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #field16-option="item">
|
<template #field16-option="{ item }">
|
||||||
<span style="float: left">{{ item.label }}</span>
|
<span style="float: left">{{ item.label }}</span>
|
||||||
<span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">{{
|
<span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
|
||||||
item.value
|
{{ item.value }}
|
||||||
}}</span>
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #field18-default="{ item }">
|
||||||
|
<span style="float: left">{{ item.label }}</span>
|
||||||
|
<span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
|
||||||
|
{{ item.value }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #field20-default="{ item }">
|
||||||
|
<span style="float: left">{{ item.label }}</span>
|
||||||
|
<span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
|
||||||
|
{{ item.value }}
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</VFrom>
|
</VFrom>
|
||||||
</ElConfigProvider>
|
</ElConfigProvider>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import { PropType, defineComponent, ref, computed, unref } from 'vue'
|
import { PropType, defineComponent, ref, computed, unref } from 'vue'
|
||||||
import { ElForm, ElFormItem, ElRow, ElCol, ElOption, ElOptionGroup } from 'element-plus'
|
import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus'
|
||||||
import { componentMap } from './componentMap'
|
import { componentMap } from './componentMap'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
import { getSlot } from '@/utils/tsxHelper'
|
import { getSlot } from '@/utils/tsxHelper'
|
||||||
import { setTextPlaceholder, setGridProp, setComponentProps, setItemComponentSlots } from './helper'
|
import { setTextPlaceholder, setGridProp, setComponentProps, setItemComponentSlots } from './helper'
|
||||||
|
import { useRenderSelect } from './components/useRenderSelect'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'VForm',
|
name: 'VForm',
|
||||||
|
@ -74,9 +75,12 @@ export default defineComponent({
|
||||||
<Com
|
<Com
|
||||||
{...(autoSetPlaceholder && setTextPlaceholder(item))}
|
{...(autoSetPlaceholder && setTextPlaceholder(item))}
|
||||||
{...setComponentProps(item.componentProps)}
|
{...setComponentProps(item.componentProps)}
|
||||||
|
// 单独给SelectV2做判断
|
||||||
|
options={item.component === 'SelectV2' ? item.options || [] : undefined}
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
default: () => (item.options ? renderOptions(item) : null),
|
default: () =>
|
||||||
|
item.options && item.component !== 'SelectV2' ? renderOptions(item) : undefined,
|
||||||
...setItemComponentSlots(slots, item?.componentProps?.slots, item.field)
|
...setItemComponentSlots(slots, item?.componentProps?.slots, item.field)
|
||||||
}}
|
}}
|
||||||
</Com>
|
</Com>
|
||||||
|
@ -90,52 +94,13 @@ export default defineComponent({
|
||||||
function renderOptions(item: VFormSchema) {
|
function renderOptions(item: VFormSchema) {
|
||||||
switch (item.component) {
|
switch (item.component) {
|
||||||
case 'Select':
|
case 'Select':
|
||||||
|
const { renderSelectOptions } = useRenderSelect(slots)
|
||||||
return renderSelectOptions(item)
|
return renderSelectOptions(item)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染 select options
|
|
||||||
function renderSelectOptions(item: VFormSchema) {
|
|
||||||
// 如果有别名,就取别名
|
|
||||||
const labelAlias = item.optionsField?.labelField
|
|
||||||
return item.options?.map((option) => {
|
|
||||||
if (option?.options?.length) {
|
|
||||||
return (
|
|
||||||
<ElOptionGroup label={labelAlias ? option[labelAlias] : option['label']}>
|
|
||||||
{() => {
|
|
||||||
return option?.options?.map((v) => {
|
|
||||||
return renderSelectOptionItem(item, v)
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</ElOptionGroup>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return renderSelectOptionItem(item, option)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 渲染 select option item
|
|
||||||
function renderSelectOptionItem(item: VFormSchema, option: FormOptions) {
|
|
||||||
// 如果有别名,就取别名
|
|
||||||
const labelAlias = item.optionsField?.labelField
|
|
||||||
const valueAlias = item.optionsField?.valueField
|
|
||||||
return (
|
|
||||||
<ElOption
|
|
||||||
label={labelAlias ? option[labelAlias] : option['label']}
|
|
||||||
value={valueAlias ? option[valueAlias] : option['value']}
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
default: () =>
|
|
||||||
// option 插槽名规则,{field}-option
|
|
||||||
item.optionsSlot ? getSlot(slots, `${item.field}-option`, option) : null
|
|
||||||
}}
|
|
||||||
</ElOption>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤传入Form组件的属性
|
// 过滤传入Form组件的属性
|
||||||
function getFormBindValue() {
|
function getFormBindValue() {
|
||||||
// 避免在标签上出现多余的属性
|
// 避免在标签上出现多余的属性
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { ElOption, ElOptionGroup } from 'element-plus'
|
||||||
|
import { getSlot } from '@/utils/tsxHelper'
|
||||||
|
import { Slots } from 'vue'
|
||||||
|
|
||||||
|
export function useRenderSelect(slots: Slots) {
|
||||||
|
// 渲染 select options
|
||||||
|
function renderSelectOptions(item: VFormSchema) {
|
||||||
|
// 如果有别名,就取别名
|
||||||
|
const labelAlias = item.optionsField?.labelField
|
||||||
|
return item.options?.map((option) => {
|
||||||
|
if (option?.options?.length) {
|
||||||
|
return (
|
||||||
|
<ElOptionGroup label={labelAlias ? option[labelAlias] : option['label']}>
|
||||||
|
{() => {
|
||||||
|
return option?.options?.map((v) => {
|
||||||
|
return renderSelectOptionItem(item, v)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</ElOptionGroup>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return renderSelectOptionItem(item, option)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染 select option item
|
||||||
|
function renderSelectOptionItem(item: VFormSchema, option: FormOptions) {
|
||||||
|
// 如果有别名,就取别名
|
||||||
|
const labelAlias = item.optionsField?.labelField
|
||||||
|
const valueAlias = item.optionsField?.valueField
|
||||||
|
return (
|
||||||
|
<ElOption
|
||||||
|
label={labelAlias ? option[labelAlias] : option['label']}
|
||||||
|
value={valueAlias ? option[valueAlias] : option['value']}
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
default: () =>
|
||||||
|
// option 插槽名规则,{field}-option
|
||||||
|
item.optionsSlot ? getSlot(slots, `${item.field}-option`, { item: option }) : undefined
|
||||||
|
}}
|
||||||
|
</ElOption>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
renderSelectOptions
|
||||||
|
}
|
||||||
|
}
|
|
@ -117,3 +117,5 @@ export function setItemComponentSlots(
|
||||||
}
|
}
|
||||||
return slotObj
|
return slotObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setModel() {}
|
||||||
|
|
|
@ -16,6 +16,7 @@ export default {
|
||||||
position: 'Position',
|
position: 'Position',
|
||||||
autocomplete: 'Autocomplete',
|
autocomplete: 'Autocomplete',
|
||||||
select: 'Select',
|
select: 'Select',
|
||||||
group: 'Select Group'
|
group: 'Select Group',
|
||||||
|
selectV2: 'SelectV2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ export default {
|
||||||
position: '位置',
|
position: '位置',
|
||||||
autocomplete: '自动补全',
|
autocomplete: '自动补全',
|
||||||
select: '选择器',
|
select: '选择器',
|
||||||
group: '选项分组'
|
group: '选项分组',
|
||||||
|
selectV2: '虚拟列表选择器'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue