wip(VForm): VForm component development

This commit is contained in:
陈凯龙 2021-12-16 14:32:20 +08:00
parent cdb5c5f0b1
commit d71bc5d6f5
4 changed files with 156 additions and 36 deletions

View File

@ -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

View File

@ -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>

View File

@ -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>
) )
}} }}

View File

@ -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
}