用el-form封装动态生成的搜索框,带校验
效果如下
el-form 结合 el-input,el-radio…常见搜索框
重点:el-form需要初始化值,form需要定义对应的ref,初次加载需要清空validate。prop,form的值需对应。
//使用
import searchComponent from "@/[组件的位置]";
<searchComponent :searchItems="Object.values(searchItems)"
:defaultSpan="24"
:form-config="{labelPosition:'left'}"
@handleSelect="handleSelect"
ref="searchComponentRef"
class="searchComponent"/>
//searchItems定义为对象,方便后续获取和修改值
const searchItems = ref({
[自己定义的key,很重要]: {
//外面表单层的组件
type: 'select', //控件类型
labelName: '',
key: '', //[自己定义的key,需要在el-form和获取搜索框值时都会使用到
rules: [], //el-form中的rules
config: { //传到组件最里边的配置数据
key: 'TrainingDegree',
options: radioArray,
value:'' //初始值
}
}})
/**fake data*/
const searchItems = ref({
StaffTeam: {
type: 'select',
labelName: 'Staff Team',
key: 'StaffTeam',
rules: [{
required: true,
message: 'please select Staff Team',
trigger: 'change'
}],
config: {
key: 'StaffTeam',
options: [],
cascader: 'Skill',
disabled: false,
multiple: true,
}
}})
/**
获取搜索条件的值的方法**/
const handleSelect = ({val, key}) => {
//searchItems中自己定义的key
searchValue.value[key] = val
// setTrainingInfor(searchValue.value)
}
searchComponent 的 index.vue文件
<template>
<el-form
ref="ruleFormRef"
:model="form"
:rules="rules"
:label-width="formConfig.labelWidth || 'auto'"
:label-position="formConfig.labelPosition || 'right'"
class="demo-ruleForm searchComponent"
status-icon>
<el-col v-for="(item,index) in searchItems"
:key="index"
:span="!!item.defaultSpan ? item.defaultSpan : defaultSpan"
:style="item.style"
class="flex-row">
<el-form-item :label="item.labelName" class="labelName"
:prop="item.key">
<component :is="item.type"
:config="item.config"
@handleSelect="handleSelect"/>
</el-form-item>
</el-col>
</el-form>
</template>
<script lang="ts">
import select from "../searchComponent/component/select.vue"
import input from "../searchComponent/component/input.vue"
import button from "../searchComponent/component/button.vue"
import daterange from "../searchComponent/component/daterange.vue"
import radio from "../searchComponent/component/radio.vue"
import inputNumber from "../searchComponent/component/inputNumber.vue"
import {nextTick, onMounted, reactive, ref,onUpdated, watch} from "vue";
interface SearchItems {
type: string, //控件类型
labelName: string, //控件显示名称
defaultSpan?: number,
style?: string, //控件特殊的css
}
export default {
name: "index",
components: {select, input, button, daterange, radio, inputNumber},
props: {
defaultSpan: { //默认占的格子数
type: Number,
default: 6
},
searchItems: { //生成的搜索框基本配置
type: Array,
default: () => ([])
},
formConfig: { //表格的基本配置,遵循原本el-form的参数
type: Object,
default: () => ({
labelWidth: '',
labelPosition: 'right',
})
},
},
emits: ['btnClick', 'handleSelect'],
setup(props: any, {emit}: any) {
const ruleFormRef = ref()
const rules = ref({})
const form = ref({})
onMounted(() => {
props.searchItems?.map((v: any) => {
rules.value[v.key] = v.rules
})
})
onUpdated(()=>{
/**
解决首次空值自动校验的问题
**/
ruleFormRef.value.clearValidate()
ruleFormRef.value.resetFields()
})
const btnClick = (data: any) => {
emit('btnClick', data)
}
const handleSelect = (data: any) => {
form.value[data.key] = data.val
/**
解决改变值后,不自动校验的问题
**/
ruleFormRef.value.validateField(data.key)
emit('handleSelect', data)
}
return {
btnClick,
handleSelect,
ruleFormRef,
rules,
form,
}
}
}
</script>
<style scoped lang="scss">
.flex-row {
display: flex;
justify-content: flex-start;
align-items: center;
}
.searchComponent {
flex-wrap: wrap !important;
display: flex;
}
.searchComponent > > > label.el-form-item__label {
display: flex;
align-items: center;
justify-content: flex-end !important;
}
.searchComponent > > > .el-form-item__content {
width: inherit;
}
</style>
以select组件为例子
<template>
<el-select v-model="val"
clearable
filterable
@change="handleSelect"
style=" width: inherit;"
:allow-create="config.allowCreate"
:collapse-tags="config.multiple"
:placeholder="config.placeholder"
:disabled="config.disabled"
:multiple="config.multiple">
<el-option
v-for="item in config.options"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
/>
</el-select>
</template>
<script>
import {onMounted, ref, watch} from "vue";
export default {
name: "select",
props: {
item: Object, //组件外层基本数据
config: { //基本配置,与element-plus一样
type: Object,
default: () => ({
value: '', //初始值
key: '',
options: Array, //选项下拉值
placeholder: 'please select',
disabled: false, //禁用
multiple: false, //开启多选
allowCreate: false, //允许自定义选项
cascader: null, //级联控制的组件的key
})
}
},
emits: ['handleSelect'],
setup(props, {emit}) {
const val = ref('')
watch(() => props.config.value, newVal => {
val.value = newVal
}, {immediate: true})
watch(() => props.config.value, newVal => {
val.value = newVal
let obj = {
key: props.config.key,
item: props.item,
config: {
cascader: props.config.cascader
}
}
emit("handleSelect", obj)
}, {immediate: true})
const handleSelect = () => {
let obj = {
val: val.value,
key: props.config.key,
item: props.item, //外层组件的数据,比如这个select套在table里面,这里就是table的行内数据
config: {
cascader: props.config.cascader,
value:val.value
}
}
props.config.value = val.value
emit("handleSelect", obj)
}
onMounted(() => {
})
return {
val,
handleSelect
}
}
}
</script>
Thanks~