wip(VForm): VForm component development
This commit is contained in:
parent
cdb5c5f0b1
commit
d71bc5d6f5
|
@ -24,6 +24,7 @@ specifiers:
|
|||
less: ^4.1.2
|
||||
lint-staged: ^12.1.2
|
||||
lodash-es: ^4.17.21
|
||||
normalize.css: ^8.0.1
|
||||
pinia: ^2.0.6
|
||||
postcss: ^8.4.4
|
||||
postcss-html: ^1.3.0
|
||||
|
@ -54,6 +55,7 @@ dependencies:
|
|||
'@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
|
||||
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
|
||||
vue: registry.npmmirror.com/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
|
||||
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:
|
||||
resolution:
|
||||
{
|
||||
|
@ -6961,7 +6974,7 @@ packages:
|
|||
{
|
||||
integrity: sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=,
|
||||
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
|
||||
version: 7.4.1
|
||||
|
@ -6974,7 +6987,7 @@ packages:
|
|||
{
|
||||
integrity: sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==,
|
||||
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
|
||||
version: 8.6.0
|
||||
|
@ -7912,7 +7925,7 @@ packages:
|
|||
{
|
||||
integrity: sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=,
|
||||
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
|
||||
version: 1.3.0
|
||||
|
@ -7924,7 +7937,7 @@ packages:
|
|||
{
|
||||
integrity: sha1-9lMoJZMFknOSyTjtROsKXJsr0wM=,
|
||||
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
|
||||
version: 2.1.0
|
||||
|
|
84
src/App.vue
84
src/App.vue
|
@ -1,42 +1,86 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted, unref, reactive } from 'vue'
|
||||
import { ElConfigProvider } from 'element-plus'
|
||||
import { reactive } from 'vue'
|
||||
import { ElConfigProvider, ElIcon } from 'element-plus'
|
||||
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
|
||||
// import en from 'element-plus/lib/locale/lang/en'
|
||||
import { VFrom, VFormExpose } from '@/components/Form'
|
||||
const formRef = ref<ComponentRef<typeof VFrom> & VFormExpose>()
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
const { t } = useI18n()
|
||||
import { VFrom } from '@/components/Form'
|
||||
import Calendar from '~icons/ep/calendar'
|
||||
|
||||
onMounted(() => {
|
||||
const form = unref(formRef.value)
|
||||
console.log(form)
|
||||
})
|
||||
const schema = reactive<VFormSchema[]>([
|
||||
{
|
||||
field: 'field1',
|
||||
component: 'Divider',
|
||||
componentProps: {
|
||||
text: 'input示例'
|
||||
text: 'Input'
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'field2',
|
||||
label: '字段1',
|
||||
label: 'default',
|
||||
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>
|
||||
|
||||
<template>
|
||||
<ElConfigProvider :locale="zhCn">
|
||||
<!-- <VFrom ref="formRef" is-custom>
|
||||
<template #default> hahahah </template>
|
||||
</VFrom> -->
|
||||
<VFrom :schema="schema" />
|
||||
<!-- <VFrom :is-col="false" :schema="schema" /> -->
|
||||
<!-- <Component :is="VFrom" /> -->
|
||||
<!-- <RouterView class="app" /> -->
|
||||
<div>{{ t('common.inputText') }}</div>
|
||||
<VFrom :schema="schema">
|
||||
<template #field4-prefix>
|
||||
<ElIcon class="el-input__icon"><Calendar /></ElIcon>
|
||||
</template>
|
||||
<template #field4-suffix>
|
||||
<ElIcon class="el-input__icon"><Calendar /></ElIcon>
|
||||
</template>
|
||||
|
||||
<template #field5-prepend> Http:// </template>
|
||||
<template #field5-append> .com </template>
|
||||
</VFrom>
|
||||
</ElConfigProvider>
|
||||
</template>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus'
|
|||
import { COMPONENT_MAP } from './componentMap'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { getSlot } from '@/utils/tsxHelper'
|
||||
import { setTextPlaceholder, setGridProp } from './helper'
|
||||
import { setTextPlaceholder, setGridProp, setComponentProps, setItemComponentSlots } from './helper'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'VForm',
|
||||
|
@ -12,7 +12,7 @@ export default defineComponent({
|
|||
// 生成Form的布局结构数组
|
||||
schema: {
|
||||
type: Array as PropType<VFormSchema[]>,
|
||||
require: true,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
// 是否需要栅格布局
|
||||
|
@ -25,7 +25,9 @@ export default defineComponent({
|
|||
// 是否自动设置placeholder
|
||||
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 }) {
|
||||
const formRef = ref<ComponentRef<typeof ElForm>>()
|
||||
|
@ -81,8 +83,15 @@ export default defineComponent({
|
|||
typeof defineComponent
|
||||
>
|
||||
return (
|
||||
<Com vModel={test.value} {...(autoSetPlaceholder && setTextPlaceholder(item))}>
|
||||
{item.options ? renderOptions() : null}
|
||||
<Com
|
||||
vModel={test.value}
|
||||
{...(autoSetPlaceholder && setTextPlaceholder(item))}
|
||||
{...setComponentProps(item.componentProps)}
|
||||
>
|
||||
{{
|
||||
default: () => (item.options ? renderOptions() : null),
|
||||
...setItemComponentSlots(slots, item?.componentProps?.slots, item.field)
|
||||
}}
|
||||
</Com>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
const { t } = useI18n()
|
||||
import { shallowRef } from 'vue'
|
||||
import { isFunction } from '@/utils/is'
|
||||
import { Slots } from 'vue'
|
||||
import { getSlot } from '@/utils/tsxHelper'
|
||||
|
||||
interface PlaceholderMoel {
|
||||
placeholder?: string
|
||||
|
@ -52,14 +56,64 @@ export function setTextPlaceholder(schema: VFormSchema): PlaceholderMoel {
|
|||
*/
|
||||
export function setGridProp(col: ColProps = {}): ColProps {
|
||||
const colProps: ColProps = {
|
||||
...{
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 8
|
||||
},
|
||||
// 如果有span,代表用户优先级更高,所以不需要默认栅格
|
||||
...(col.span
|
||||
? {}
|
||||
: {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 8
|
||||
}),
|
||||
...col
|
||||
}
|
||||
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