wip(VForm): VForm component development
This commit is contained in:
parent
cdb5c5f0b1
commit
d71bc5d6f5
|
@ -24,6 +24,7 @@ specifiers:
|
||||||
less: ^4.1.2
|
less: ^4.1.2
|
||||||
lint-staged: ^12.1.2
|
lint-staged: ^12.1.2
|
||||||
lodash-es: ^4.17.21
|
lodash-es: ^4.17.21
|
||||||
|
normalize.css: ^8.0.1
|
||||||
pinia: ^2.0.6
|
pinia: ^2.0.6
|
||||||
postcss: ^8.4.4
|
postcss: ^8.4.4
|
||||||
postcss-html: ^1.3.0
|
postcss-html: ^1.3.0
|
||||||
|
@ -54,6 +55,7 @@ dependencies:
|
||||||
'@vueuse/core': registry.npmmirror.com/@vueuse/core/7.1.2_vue@3.2.24
|
'@vueuse/core': registry.npmmirror.com/@vueuse/core/7.1.2_vue@3.2.24
|
||||||
element-plus: registry.npmmirror.com/element-plus/1.2.0-beta.6_vue@3.2.24
|
element-plus: registry.npmmirror.com/element-plus/1.2.0-beta.6_vue@3.2.24
|
||||||
lodash-es: registry.nlark.com/lodash-es/4.17.21
|
lodash-es: registry.nlark.com/lodash-es/4.17.21
|
||||||
|
normalize.css: registry.nlark.com/normalize.css/8.0.1
|
||||||
pinia: registry.npmmirror.com/pinia/2.0.6_typescript@4.5.2+vue@3.2.24
|
pinia: registry.npmmirror.com/pinia/2.0.6_typescript@4.5.2+vue@3.2.24
|
||||||
vue: registry.npmmirror.com/vue/3.2.24
|
vue: registry.npmmirror.com/vue/3.2.24
|
||||||
vue-i18n: registry.npmmirror.com/vue-i18n/9.1.9_vue@3.2.24
|
vue-i18n: registry.npmmirror.com/vue-i18n/9.1.9_vue@3.2.24
|
||||||
|
@ -3347,6 +3349,17 @@ packages:
|
||||||
version: 0.2.0
|
version: 0.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.nlark.com/normalize.css/8.0.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha1-m5iiCHOLnMJjTKrLxC0THJdIe/M=,
|
||||||
|
registry: https://registry.npm.taobao.org/,
|
||||||
|
tarball: https://registry.nlark.com/normalize.css/download/normalize.css-8.0.1.tgz
|
||||||
|
}
|
||||||
|
name: normalize.css
|
||||||
|
version: 8.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.nlark.com/nth-check/2.0.1:
|
registry.nlark.com/nth-check/2.0.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
@ -6961,7 +6974,7 @@ packages:
|
||||||
{
|
{
|
||||||
integrity: sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=,
|
integrity: sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=,
|
||||||
registry: https://registry.npm.taobao.org/,
|
registry: https://registry.npm.taobao.org/,
|
||||||
tarball: https://registry.npmmirror.com/acorn/download/acorn-7.4.1.tgz?cache=0&sync_timestamp=1637226362293&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Facorn%2Fdownload%2Facorn-7.4.1.tgz
|
tarball: https://registry.npmmirror.com/acorn/download/acorn-7.4.1.tgz?cache=0&sync_timestamp=1637225943828&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Facorn%2Fdownload%2Facorn-7.4.1.tgz
|
||||||
}
|
}
|
||||||
name: acorn
|
name: acorn
|
||||||
version: 7.4.1
|
version: 7.4.1
|
||||||
|
@ -6974,7 +6987,7 @@ packages:
|
||||||
{
|
{
|
||||||
integrity: sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==,
|
integrity: sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==,
|
||||||
registry: https://registry.npm.taobao.org/,
|
registry: https://registry.npm.taobao.org/,
|
||||||
tarball: https://registry.npmmirror.com/acorn/download/acorn-8.6.0.tgz?cache=0&sync_timestamp=1637226362293&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Facorn%2Fdownload%2Facorn-8.6.0.tgz
|
tarball: https://registry.npmmirror.com/acorn/download/acorn-8.6.0.tgz?cache=0&sync_timestamp=1637225943828&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Facorn%2Fdownload%2Facorn-8.6.0.tgz
|
||||||
}
|
}
|
||||||
name: acorn
|
name: acorn
|
||||||
version: 8.6.0
|
version: 8.6.0
|
||||||
|
@ -7912,7 +7925,7 @@ packages:
|
||||||
{
|
{
|
||||||
integrity: sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=,
|
integrity: sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=,
|
||||||
registry: https://registry.npm.taobao.org/,
|
registry: https://registry.npm.taobao.org/,
|
||||||
tarball: https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz?cache=0&sync_timestamp=1636378498011&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.3.0.tgz
|
tarball: https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz?cache=0&sync_timestamp=1636378941796&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.3.0.tgz
|
||||||
}
|
}
|
||||||
name: eslint-visitor-keys
|
name: eslint-visitor-keys
|
||||||
version: 1.3.0
|
version: 1.3.0
|
||||||
|
@ -7924,7 +7937,7 @@ packages:
|
||||||
{
|
{
|
||||||
integrity: sha1-9lMoJZMFknOSyTjtROsKXJsr0wM=,
|
integrity: sha1-9lMoJZMFknOSyTjtROsKXJsr0wM=,
|
||||||
registry: https://registry.npm.taobao.org/,
|
registry: https://registry.npm.taobao.org/,
|
||||||
tarball: https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-2.1.0.tgz?cache=0&sync_timestamp=1636378498011&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-2.1.0.tgz
|
tarball: https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-2.1.0.tgz?cache=0&sync_timestamp=1636378941796&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-2.1.0.tgz
|
||||||
}
|
}
|
||||||
name: eslint-visitor-keys
|
name: eslint-visitor-keys
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
|
|
84
src/App.vue
84
src/App.vue
|
@ -1,42 +1,86 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, unref, reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { ElConfigProvider } from 'element-plus'
|
import { ElConfigProvider, ElIcon } from 'element-plus'
|
||||||
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
|
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
|
||||||
// import en from 'element-plus/lib/locale/lang/en'
|
// import en from 'element-plus/lib/locale/lang/en'
|
||||||
import { VFrom, VFormExpose } from '@/components/Form'
|
import { VFrom } from '@/components/Form'
|
||||||
const formRef = ref<ComponentRef<typeof VFrom> & VFormExpose>()
|
import Calendar from '~icons/ep/calendar'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const form = unref(formRef.value)
|
|
||||||
console.log(form)
|
|
||||||
})
|
|
||||||
const schema = reactive<VFormSchema[]>([
|
const schema = reactive<VFormSchema[]>([
|
||||||
{
|
{
|
||||||
field: 'field1',
|
field: 'field1',
|
||||||
component: 'Divider',
|
component: 'Divider',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
text: 'input示例'
|
text: 'Input'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'field2',
|
field: 'field2',
|
||||||
label: '字段1',
|
label: 'default',
|
||||||
component: 'Input'
|
component: 'Input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field3',
|
||||||
|
label: 'input-icon1',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
suffixIcon: Calendar,
|
||||||
|
prefixIcon: Calendar
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field4',
|
||||||
|
label: 'input-icon2',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
slots: {
|
||||||
|
suffix: true,
|
||||||
|
prefix: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field5',
|
||||||
|
label: 'input-mixed',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
slots: {
|
||||||
|
prepend: true,
|
||||||
|
append: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field6',
|
||||||
|
label: 'textarea',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field7',
|
||||||
|
component: 'Divider',
|
||||||
|
componentProps: {
|
||||||
|
text: 'Autocomplete'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElConfigProvider :locale="zhCn">
|
<ElConfigProvider :locale="zhCn">
|
||||||
<!-- <VFrom ref="formRef" is-custom>
|
<VFrom :schema="schema">
|
||||||
<template #default> hahahah </template>
|
<template #field4-prefix>
|
||||||
</VFrom> -->
|
<ElIcon class="el-input__icon"><Calendar /></ElIcon>
|
||||||
<VFrom :schema="schema" />
|
</template>
|
||||||
<!-- <VFrom :is-col="false" :schema="schema" /> -->
|
<template #field4-suffix>
|
||||||
<!-- <Component :is="VFrom" /> -->
|
<ElIcon class="el-input__icon"><Calendar /></ElIcon>
|
||||||
<!-- <RouterView class="app" /> -->
|
</template>
|
||||||
<div>{{ t('common.inputText') }}</div>
|
|
||||||
|
<template #field5-prepend> Http:// </template>
|
||||||
|
<template #field5-append> .com </template>
|
||||||
|
</VFrom>
|
||||||
</ElConfigProvider>
|
</ElConfigProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus'
|
||||||
import { COMPONENT_MAP } from './componentMap'
|
import { COMPONENT_MAP } 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 } from './helper'
|
import { setTextPlaceholder, setGridProp, setComponentProps, setItemComponentSlots } from './helper'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'VForm',
|
name: 'VForm',
|
||||||
|
@ -12,7 +12,7 @@ export default defineComponent({
|
||||||
// 生成Form的布局结构数组
|
// 生成Form的布局结构数组
|
||||||
schema: {
|
schema: {
|
||||||
type: Array as PropType<VFormSchema[]>,
|
type: Array as PropType<VFormSchema[]>,
|
||||||
require: true,
|
required: true,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
// 是否需要栅格布局
|
// 是否需要栅格布局
|
||||||
|
@ -25,7 +25,9 @@ export default defineComponent({
|
||||||
// 是否自动设置placeholder
|
// 是否自动设置placeholder
|
||||||
autoSetPlaceholder: propTypes.bool.def(true),
|
autoSetPlaceholder: propTypes.bool.def(true),
|
||||||
// 是否自定义内容
|
// 是否自定义内容
|
||||||
isCustom: propTypes.bool.def(false)
|
isCustom: propTypes.bool.def(false),
|
||||||
|
// 表单label宽度
|
||||||
|
labelWidth: propTypes.oneOfType([String, Number]).def(130)
|
||||||
},
|
},
|
||||||
setup(props, { slots }) {
|
setup(props, { slots }) {
|
||||||
const formRef = ref<ComponentRef<typeof ElForm>>()
|
const formRef = ref<ComponentRef<typeof ElForm>>()
|
||||||
|
@ -81,8 +83,15 @@ export default defineComponent({
|
||||||
typeof defineComponent
|
typeof defineComponent
|
||||||
>
|
>
|
||||||
return (
|
return (
|
||||||
<Com vModel={test.value} {...(autoSetPlaceholder && setTextPlaceholder(item))}>
|
<Com
|
||||||
{item.options ? renderOptions() : null}
|
vModel={test.value}
|
||||||
|
{...(autoSetPlaceholder && setTextPlaceholder(item))}
|
||||||
|
{...setComponentProps(item.componentProps)}
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
default: () => (item.options ? renderOptions() : null),
|
||||||
|
...setItemComponentSlots(slots, item?.componentProps?.slots, item.field)
|
||||||
|
}}
|
||||||
</Com>
|
</Com>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
import { shallowRef } from 'vue'
|
||||||
|
import { isFunction } from '@/utils/is'
|
||||||
|
import { Slots } from 'vue'
|
||||||
|
import { getSlot } from '@/utils/tsxHelper'
|
||||||
|
|
||||||
interface PlaceholderMoel {
|
interface PlaceholderMoel {
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
|
@ -52,14 +56,64 @@ export function setTextPlaceholder(schema: VFormSchema): PlaceholderMoel {
|
||||||
*/
|
*/
|
||||||
export function setGridProp(col: ColProps = {}): ColProps {
|
export function setGridProp(col: ColProps = {}): ColProps {
|
||||||
const colProps: ColProps = {
|
const colProps: ColProps = {
|
||||||
...{
|
// 如果有span,代表用户优先级更高,所以不需要默认栅格
|
||||||
|
...(col.span
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
xs: 24,
|
xs: 24,
|
||||||
sm: 12,
|
sm: 12,
|
||||||
md: 12,
|
md: 12,
|
||||||
lg: 12,
|
lg: 12,
|
||||||
xl: 8
|
xl: 8
|
||||||
},
|
}),
|
||||||
...col
|
...col
|
||||||
}
|
}
|
||||||
return colProps
|
return colProps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ComponentPropsModel = {
|
||||||
|
clearable: boolean
|
||||||
|
} & Recordable
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param props 传入的组件属性
|
||||||
|
* @returns 默认添加 clearable 属性
|
||||||
|
*/
|
||||||
|
export function setComponentProps(props: Recordable = {}): ComponentPropsModel {
|
||||||
|
for (const key in props) {
|
||||||
|
// 如果传入的是组件,需要让其失去响应式,避免不必要的性能开销
|
||||||
|
// 这样判断好像还不太合理。后续看看没有更合理的判断方法
|
||||||
|
if (props[key]?.render && isFunction(props[key]?.render)) {
|
||||||
|
props[key] = shallowRef(props[key]?.render())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const componentProps: ComponentPropsModel = {
|
||||||
|
clearable: true,
|
||||||
|
...props
|
||||||
|
}
|
||||||
|
return componentProps
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param slots 插槽
|
||||||
|
* @param slotsProps 插槽属性
|
||||||
|
* @param field 字段名
|
||||||
|
*/
|
||||||
|
export function setItemComponentSlots(
|
||||||
|
slots: Slots,
|
||||||
|
slotsProps: Recordable = {},
|
||||||
|
field: string
|
||||||
|
): Recordable {
|
||||||
|
const slotObj: Recordable = {}
|
||||||
|
for (const key in slotsProps) {
|
||||||
|
if (slotsProps[key]) {
|
||||||
|
// 由于组件有可能重复,需要有一个唯一的前缀
|
||||||
|
slotObj[key] = () => {
|
||||||
|
return getSlot(slots, `${field}-${key}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slotObj
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue