类似这样的表单如果有多个地方使用的话,最好封装起来,直接上代码
一.首先创建一个form 文件,类似这样结构
1.form.vue
<template>
<div class="hy-form">
<div class="header">
<slot name="header"></slot>
</div>
<el-form :label-width="labelWidth">
<el-row>
<template v-for="item in formItems" :key="item.label">
<el-col v-bind="colLayout">
<el-form-item
:label="item.label"
:rules="item.rules"
:style="itemStyle"
>
<template
v-if="item.type === 'input' || item.type === 'password'"
>
<el-input
:placeholder="item.placeholder"
v-bind="item.otherOptions"
:show-password="item.type === 'password'"
v-model="formData[`${item.field}`]"
/>
</template>
<template v-else-if="item.type === 'select'">
<el-select
:placeholder="item.placeholder"
v-bind="item.otherOptions"
style="width: 100%"
v-model="formData[`${item.field}`]"
>
<el-option
v-for="option in item.options"
:key="option.value"
:value="option.value"
>{{ option.title }}</el-option
>
</el-select>
</template>
<template v-else-if="item.type === 'datepicker'">
<el-date-picker
style="width: 100%"
v-bind="item.otherOptions"
v-model="formData[`${item.field}`]"
></el-date-picker>
</template>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watch } from 'vue'
import { IFormItem } from '../types'
export default defineComponent({
props: {
modelValue: {
type: Object,
required: true
},
formItems: {
type: Array as PropType<IFormItem[]>,
default: () => []
},
labelWidth: {
type: String,
default: '100px'
},
itemStyle: {
type: Object,
default: () => ({ padding: '10px 40px' })
},
colLayout: {
type: Object,
default: () => ({
xl: 6,
lg: 8,
md: 12,
sm: 24,
xs: 24
})
}
},
emits: ['update:modelValue'],
setup(props, { emit }) {
const formData = ref({ ...props.modelValue })
watch(
formData,
(newValue) => {
emit('update:modelValue', newValue)
},
{
deep: true
}
)
return {
formData
}
}
})
</script>
<style scoped lang="less">
.hy-form {
padding-top: 22px;
}
</style>
2.types文件中的index.ts
type IFormType = 'input' | 'password' | 'select' | 'datepicker'
export interface IFormItem {
field: string
type: IFormType
label: string
rules?: any[]
placeholder?: any
options?: any[]
otherOptions?: any
}
export interface IForm {
formItems: IFormItem[]
labelWidth?: string
colLayout?: any
itemLayout?: any
}
3.index.ts 导出
import HyForm from './src/form.vue'
export * from './types'
export default HyForm
二.因为我是比较喜欢拆分,所以每个页面单独又创建了一个组件page-search.vue
<template>
<div class="page-search">
<hy-form v-bind="searchFormConfig" v-model="formData">
<template
<h1 class="header">高级检索</h1>
</template>
<template
<div class="handle-btns">
<el-button icon="el-icon-refresh" @click="handleResetClick"
>重置</el-button
>
<el-button type="primary" icon="el-icon-search">搜索</el-button>
</div>
</template>
</hy-form>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import HyForm from '@/base-ui/form'
export default defineComponent({
props: {
searchFormConfig: {
type: Object,
reuqired: true
}
},
components: {
HyForm
},
setup(props) {
// 双向绑定的属性应该是由配置文件的field来决定
// 1.优化一: formData中的属性应该动态来决定
const formItems = props.searchFormConfig?.formItems ?? []
const formOriginData: any = {}
for (const item of formItems) {
formOriginData[item.field] = ''
}
const formData = ref(formOriginData)
// 2.优化二: 当用户点击重置
const handleResetClick = () => {
for (const key in formOriginData) {
formData.value[`${key}`] = formOriginData[key]
}
}
return {
formData,
handleResetClick
}
}
})
</script>
<style scoped>
.header {
color: red;
}
.handle-btns {
text-align: right;
padding: 0 50px 20px 0;
}
</style>
三.然后就是每个页面使用了
先创建一个search.config.ts配置项
import { IForm } from '@/base-ui/form'
export const searchFormConfig: IForm = {
labelWidth: '120px',
itemLayout: {
padding: '10px 40px'
},
colLayout: {
span: 8
},
formItems: [
{
field: 'id',
type: 'input',
label: 'id',
placeholder: '请输入id'
},
{
field: 'name',
type: 'input',
label: '用户名',
placeholder: '请输入用户名'
},
{
field: 'password',
type: 'password',
label: '密码',
placeholder: '请输入密码'
},
{
field: 'sport',
type: 'select',
label: '喜欢的运动',
placeholder: '请选择喜欢的运动',
options: [
{ title: '篮球', value: 'basketball' },
{ title: '足球', value: 'football' }
]
},
{
field: 'createTime',
type: 'datepicker',
label: '创建时间',
otherOptions: {
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
type: 'daterange'
}
}
]
}
然后使用即可
<page-search :searchFormConfig="searchFormConfig" />
再之后所有的表单页面都通过配置项来编写,只需要改变search.config.ts中的配置即可
|