概要
当使用a-form-model组件进行表单数据绑定时,可以使用自定义组件封装一个通用的表单组件,将其作为一个单独的模块进行复用。以下是对给定代码的详细解析
整体架构流程
-
在模板部分,使用
a-form-model
包裹表单元素,并在其ref
属性设置为"ruleForm",以方便在代码中对该表单进行操作。 -
使用
a-row
和a-col
组件来布局表单项,通过v-for
指令循环渲染formItems
中的每个表单项。 -
对于每个表单项,使用
a-form-model-item
组件来包裹该项,并通过传递属性来设置该项的验证规则和其他属性。该项的组件类型由item.type
决定,通过componentMap
对象进行映射。 -
在模板中使用
component
标签来动态渲染相应的组件,并通过v-model
指令绑定formInline
对象中对应的属性。 -
在事件处理器中,
handleDateChange
方法用于处理日期选择器的改变事件,并将选择的日期值存储到formInline
对象中。 -
handleSubmit
方法用于处理表单的提交事件,通过验证表单的合法性后,将当前表单的值通过$emit
方法发送给父组件。 -
handleReset
方法用于重置表单,通过resetFields
方法将表单重置为初始状态。 -
在
created
生命周期钩子中,遍历formItems
数组,并根据具体的表单项类型进行初始化操作,如设置默认选中第一项。 -
在样式部分,使用
scoped
属性将样式限定在当前组件内部。
用到组件
- ant-design-vue
- vue2
技术细节
组件如下,增加了高级搜索功能,目前是最多展示六个,超过六个展示高级搜索按钮
<template>
<div class="uniform-search-form">
<a-form-model
ref="ruleForm"
layout="inline"
:model="formInline"
@submit="handleSubmit"
@submit.native.prevent
class="form-container"
:label-col="{ span:6 }"
:wrapper-col="{span:18}"
>
<a-row>
<a-col
:xs="24"
:sm="12"
:md="8"
:lg="8"
:xl="8"
:span="8"
v-for="item in visibleFormItems"
:key="item.key"
>
<a-form-model-item
:ref="item.model"
:rules="item.rules"
:label="item.label"
:prop="item.model"
>
<template>
<component
style="width: 100%;"
:is="componentMap[item.type]"
v-model="formInline[item.model]"
v-bind="{ ...item.componentProps }"
:placeholder="item.placeholder"
@change="handleDateChange"
@calendarChange="getmodel(item.model)"
/>
</template>
</a-form-model-item>
</a-col>
<a-col v-if="formItems.length<=1" :xs="24"
:sm="12"
:md="8"
:lg="8"
:xl="8"
:span="8">
<a-button style="margin-right: 10px;" type="primary" icon="search" @click="handleSubmit()">
查询
</a-button>
<a-button icon="undo" @click="handleReset()">
重置
</a-button>
</a-col>
<div v-else style="text-align: right; padding-right: 20px;">
<a-button style="margin-right: 10px;" type="primary" icon="search" @click="handleSubmit()">
查询
</a-button>
<a-button icon="undo" @click="handleReset()">
重置
</a-button>
<a-button v-if="formItems.length>6" style="margin-left: 10px;" @click="toggleComplexSearch">
{{ complexSearchVisible ?'收起搜索':'高级搜索'}}
</a-button>
</div>
</a-row>
</a-form-model>
</div>
</template>
<script>
export default {
props:{
formItems:{
type:Array,
required:true
}
},
data() {
return {
complexSearchVisible: false, // 控制复杂搜索的展示状态
visibleFormItems: [], // 当前显示的搜索框
formInline: {},
model:'',
/* //formItems从父组件传过来 格式如下
formItems: [
// 表单项数据
{
key: 'username',
model: 'username',
label: '用户名',
type: 'input',
rules: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
componentProps: {}
},
// 其他表单项
],
*/
componentMap: {
input: 'a-input',
select:'a-select',
date:'a-date-picker',
number:'a-input-number',
autoComplete:'a-auto-complete',
treeSelect:'a-tree-select',
time:'a-time-picker',
rangePicker:'a-range-picker'
// 其他组件映射
}
};
},
computed:{
isFormValid(){
return Object.values(this.formInline).every((value)=> value !== '')
}
},
watch:{
formItems: {
handler(newVal) {
this.updateVisibleFormItems();
},
immediate: true
}
},
methods: {
toggleComplexSearch() {
this.complexSearchVisible = !this.complexSearchVisible;
this.updateVisibleFormItems();
},
updateVisibleFormItems() {
if (this.complexSearchVisible || this.formItems.length <= 6) {
this.visibleFormItems = this.formItems;
} else {
this.visibleFormItems = this.formItems.slice(0, 6);
}
},
getmodel(model){
this.model = model
},
handleDateChange(dates,dateStrings){
if(dates && dates.length===2){
const startDate = dateStrings[0]
const endDate = dateStrings[1]
this.formInline[this.model]= [startDate,endDate]
}
},
handleSubmit(e) {
this.$refs.ruleForm.validate(valid => {
if (valid) {
alert('提交成功!');
//这里就是表单的值 传到父组件去作为搜索条件
this.$emit('submit',this.formInline)
} else {
console.log('验证失败');
return false;
}
});
},
handleReset(){
this.$refs.ruleForm.resetFields()
this.formInline={}
}
},
created(){
this.formItems.forEach((item) => {
if (item.type==='select'&& item.isSelect) {
//设置默认选中第一项
this.$set(this.formInline,item.model,item.componentProps.options[0].value)
}
});
this.updateVisibleFormItems();
}
};
</script>
<style scoped lang="less">
.uniform-search-form{
display: flex;
flex-direction: column;
align-items: flex-start;
}
.form-container{
width: 100%;
}
</style>
直接引入使用
主要就是不同type需要传递什么searchFormItems参数,具体如下
<template>
<uniform-search-form :formItems="searchFormItems" @submit="onSubmit"></uniform-search-form>
</template>
<script>
import UniformSearchForm from './UniformSearchForm.vue';
export default {
components: {
UniformSearchForm
},
data() {
return {
searchFormItems: [
// 输入框
{
key: 'username',//作为唯一值,请与model保持一致,不写也不会报错
model: 'username',//这个是字段的名字,搜索参数直接传递给后台的,跟之前的v-decorator/v-model一样
label: '用户名',//左侧label值
type: 'input',//输入框类型
placeholder: '请输入用户名',
rules: [{ required: true, message: '请输入用户名', trigger: 'blur' }],//校验
componentProps: { allowClear: true }//这个里面写输入框的各个属性,具体可参考下面案例
}
// 下拉选择框
{
key: 'city',
model: 'city',
label: '城市',
type: 'select',
placeholder: '请选择城市',
isSelect:true,//默认展示下拉搜索第一项
componentProps: {
options: [
{ value: 'beijing', label: '北京' },
{ value: 'shanghai', label: '上海' },
// 其他选项...
],//这里就是下拉选项
allowClear: true
},
rules: [{ required: true, message: '请选择城市', trigger: 'change' }]
}
// 日期选择器
{
key: 'startDate',
model: 'startDate',
label: '开始日期',
type: 'date',
placeholder: '请选择开始日期',
rules: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
componentProps: { format: 'YYYY-MM-DD' }
}
// 日期范围选择器
{
key: 'dateRange',
model: 'dateRange',
label: '日期范围',
type: 'RangePicker',
placeholder: ['开始日期', '结束日期'],
rules: [{ required: true, message: '请选择日期范围', trigger: 'change' }],
componentProps: { format: 'YYYY-MM-DD' }
}
};
},
methods: {
onSubmit(formData) {
// 处理表单提交
//这里可以直接调用搜索方法 formData即传递出的参数,如果需要特殊处理 处理具体表单项即可!
console.log('表单数据:', formData);
}
}
};
</script>
小结
本组件实现了搜索按钮一直居右展示 占三分之一 只有一个搜索框让搜索按钮紧跟着搜索框,超过六个搜索框就会有高级搜索按钮
最终效果: