element plus封装动态生成的搜索框,带校验

用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~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值