基于Ant Design of Vue的粗糙组件封装-可收起展开的条件表单

概要

由于开发工作需求中,很多的列表页都会有很多查询筛选条件的备选,但是其实查询筛选过程只需要选填查询筛选条件,不需要全部填,这种一大堆的条件选择及输入组件全部堆到一起。导致重要常用的几个筛选条件很难被找到,为了突出重点,结合大家的使用情况,可以将不常用的筛选条件折叠起来,需要更多筛选条件查询的时候再展开使用。

整体架构流程

当前这个可伸展的条件选择组件,主要是基于Ant Design of Vue组件库封装的。由于都是一些表单组件,所以外层主要使用的也就是antd的FormModel 表单组件,表单元素的布局我使用的是Grid 栅格布局。

技术细节

整体代码

<!--
 * @description GFlexibleConditionsForm.vue 可伸缩的条件填写表单
 * @author JUN - 2023/8/11 9:20
-->
<template>
    <div :class="advanced ? 'search' : null">
        <a-form-model ref="flexibleConditionsForm" :model="formData" v-bind="$attrs">
            <!--展开显示-->
            <div v-if="advanced">
                <slot name="extend" v-bind="{formData}">
                    <!--为每一个formItem动态添加一个slot插槽,方便布局和控制(插槽的名称例如:“item_2_3”,表示第二行第三列的formItem)-->
                    <template v-for="rowIndex in rowCount">
                        <a-row :key="rowIndex">
                            <template v-for="colIndex in colCount">
                                <a-col :key="colIndex" v-bind="{...colOptions}">
                                    <slot :name="`item_${rowIndex}_${colIndex}`" v-bind="{rowIndex,colIndex,advanced}"></slot>
                                </a-col>
                            </template>
                            <a-col></a-col>
                        </a-row>
                    </template>
                </slot>
            </div>

            <!--收起显示-->
            <div v-else class="fold">
                <slot name="shrink" v-bind="{formData}">
                    <!--为每一个formItem动态添加一个slot插槽,方便布局和控制(插槽的名称例如:“item_2_3”,表示第二行第三列的formItem)-->
                    <template v-for="rowIndex in rowCount">
                        <a-row :key="rowIndex">
                            <template v-for="colIndex in colCount">
                                <a-col :key="colIndex" v-bind="{...colOptions}">
                                    <slot :name="`item_${rowIndex}_${colIndex}_retain`" v-bind="{rowIndex,colIndex,advanced}"></slot>
                                </a-col>
                            </template>
                            <a-col></a-col>
                        </a-row>
                    </template>
                </slot>
            </div>

            <slot v-bind="{formData}"></slot>

            <slot name="operator" v-if="operator+''!=='null'">
                <div style="float: right; margin-top: 3px;">
                    <a-button :type="okType" @click.prevent="onSubmitForm()">{{okText}}</a-button>
                    <a-button style="margin-left: 8px" @click.prevent="onResetForm()">{{cancelText}}</a-button>
                    <a @click="onToggleAdvanced()" style="margin-left: 8px">
                        {{ advanced ? '收起' : '展开' }}
                        <a-icon :type="advanced ? 'up' : 'down'"/>
                    </a>
                </div>
            </slot>

        </a-form-model>
    </div>
</template>
<script lang="ts">
import {
    Vue, Component, Prop, Emit, Model,
} from 'vue-property-decorator';

type colCountType = 1 | 2 | 3 | 4 | 6;

@Component({ name: 'GFlexibleConditionsForm' })
export default class GFlexibleConditionsForm extends Vue {
    /* 表单数据 */
    @Model('change', {
        type: Object,
        default: () => ({})
    }) formData: Record<string, any> | undefined;

    /* 初始化是否展开 */
    @Prop({
        type: Boolean,
        default: false
    }) isExtend: boolean | undefined;

    /* 行数(为了动态添加slot插槽使用) */
    @Prop({
        type: Number,
        default: 1
    }) rowCount: number | undefined;

    /* 列数(为了动态添加slot插槽使用) */
    @Prop({
        type: Number,
        default: 3
    }) colCount: colCountType;

    /* 确认按钮文字 */
    @Prop({
        type: String,
        default: '查询'
    }) okText: string | undefined;

    /* 确认按钮类型 */
    @Prop({
        type: String,
        default: 'primary'
    }) okType: string | undefined;

    /* 取消/重置按钮文字 */
    @Prop({
        type: String,
        default: '重置'
    }) cancelText: string | undefined;

    /* 操作表单按钮部分,当不需要默认底部按钮时,可以设为 :operator="null" */
    @Prop({
        type: String,
        default: ''
    }) operator: string | undefined;

    /* 展开更多 */
    advanced = false;

    /* a-col的设置参数 */
    get colOptions() {
        return {
            md: 24 / this.colCount, // 根据列数动态变化
            sm: 24,
        };
    }

    /**
     * @description  伸缩form事件处理
     * @return void
     * @author JUN - 2023/8/11 9:43
     */
    onToggleAdvanced() {
        this.advanced = !this.advanced;
    }

    /**
     * @description 提交表单操作
     * @return void
     * @author JUN - 2023/8/11 11:40
     */
    onSubmitForm() {
        const { flexibleConditionsForm }: any = this.$refs;
        if (flexibleConditionsForm) {
            flexibleConditionsForm.validate((valid) => {
                if (valid) {
                    this.emitSubmit({
                        formDom: flexibleConditionsForm,
                        value: this.formData,
                    });
                }
            });
        }
    }

    /**
     * @description 重置表单内容操作
     * @return void
     * @author JUN - 2023/8/11 11:41
     */
    onResetForm() {
        const { flexibleConditionsForm }: any = this.$refs;
        if (flexibleConditionsForm) {
            flexibleConditionsForm.resetFields();
            this.emitReset(flexibleConditionsForm);
        }
    }

    created() {
        this.advanced = this.isExtend;
    }

    /**
     * @description 表单提交的emit
     * @return void
     * @author JUN - 2023/8/11 11:43
     */
    @Emit('submit')
    emitSubmit(value) {
        return value;
    }

    /**
     * @description 表单重置的emit
     * @return void
     * @author JUN - 2023/8/11 11:43
     */
    @Emit('reset')
    emitReset(value) {
        return value;
    }
}
</script>

<style scoped lang="less">
.search {
  margin-bottom: 54px;
}

.fold {
  width: calc(100% - 216px);
  display: inline-block
}

@media screen and (max-width: 900px) {
  .fold {
    width: 100%;
  }
}
</style>

参数

成员说明类型默认值

formData(v-model)

表单数据

Object{}
isExtend初始化是否展开

Boolean

false
rowCount行数(为了动态添加slot插槽使用)Number1
colCount列数(为了动态添加slot插槽使用),可选 

1 | 2 | 3 | 4 | 6

Number3
okText确认按钮文字String"查询"
okType确认按钮类型String

"primary"

cancelText取消/重置按钮文字String"重置"
operator操作表单按钮部分,当不需要默认底部按钮时,可以设为 :operator="null"String""

shrink(方式一)

条件收起的时候要显示的内容展示slot插槽Slot-

extend(方式一)

条件展开的时候要显示的内容展示slot插槽Slot-
item_{rowIndex}_${colIndex} (方式二)根据rowCount和colCount动态生成的slot插槽,插槽的名称如:item_1_2表示的是第一行的第二列的slot(收缩状态)Slot-
item_{rowIndex}_${colIndex}_retain (方式二)根据rowCount和colCount动态生成的slot插槽,插槽的名称如:item_1_2表示的是第一行的第二列的slot(展开状态)Slot-

isStrictMode

动态生成表单组件slot插槽的模式选择,是否是严格模式,如果为false就不会有item_{rowIndex}_${colIndex}_retain类的插槽了

Booleantrue

事件

事件名称说明回调参数

submit

提交表单时回调,参数中formDom为当前组件表单的dom对象,formData为表单数据

function(formDom,formData)

reset

重置表单时回调,参数中formData为表单数据function(formDom)

使用

方式一

上面的参数说明里面的 shrink 和 extend 参数就是控制条件表单的伸缩显示的插槽

代码
<!--
 * @description GFlexibleConditionsFormDemo.vue   可伸缩的条件填写表单Demo(方式一)
 * @author JUN - 2023/8/11 9:21
-->
<template>
    <g-flexible-conditions-form :row-count="2" :col-count="3" v-model="formData" @submit="onSubmit" @reset="onReset">
        <a-form-model-item label="规则编号"
                           slot="shrink"
                           prop="num"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-input placeholder="请输入" v-model="formData.num"/>
        </a-form-model-item>

        <a-form-model-item label="使用状态"
                           slot="extend"
                           prop="status"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-select placeholder="请选择" v-model="formData.status">
                <a-select-option value="1">关闭</a-select-option>
                <a-select-option value="2">运行中</a-select-option>
            </a-select>
        </a-form-model-item>
    </g-flexible-conditions-form>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import GFlexibleConditionsForm from '@/components/common/forms/GFlexibleConditionsForm.vue';

@Component({
    name: 'GFlexibleConditionsFormDemo',
    components: { GFlexibleConditionsForm }
})
export default class GFlexibleConditionsFormDemo extends Vue {
    formData = {
        num: 12,
        status: undefined,
        callCount: 0,
        updateDate: undefined,
        createdDate: undefined,
        desc: undefined,
    };

    onSubmit({
                 formDom,
                 value,
             }) {
        alert(JSON.stringify(value));
    }

    onReset(formDom) {
        debugger;
    }
}
</script>

<style scoped lang="less">

</style>
收起状态(slot:shrink)

展开状态(slot:extend)

优点

表单元素添加比较灵活

缺点

需要自己布局表单元素

方式二

也是看上面的参数说明,可以根据rowCount和colCount动态生成的slot插槽(如:item_1_2),将筛选条件组件放入插槽中显示

代码
<!--
 * @description GFlexibleConditionsFormDemo.vue   可伸缩的条件填写表单Demo(方式二)
 * @author JUN - 2023/8/11 9:21
-->
<template>
    <g-flexible-conditions-form :row-count="2" :col-count="3" v-model="formData" @submit="onSubmit" @reset="onReset">
        <a-form-model-item label="规则编号"
                           slot="item_1_1"
                           prop="num"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-input placeholder="请输入" v-model="formData.num"/>
        </a-form-model-item>

        <a-form-model-item label="使用状态"
                           slot="item_1_2"
                           prop="status"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-select placeholder="请选择" v-model="formData.status">
                <a-select-option value="1">关闭</a-select-option>
                <a-select-option value="2">运行中</a-select-option>
            </a-select>
        </a-form-model-item>
        <a-form-model-item label="调用次数"
                           slot="item_1_3"
                           prop="callCount"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-input-number style="width: 100%" placeholder="请输入" v-model="formData.callCount"/>
        </a-form-model-item>
        <a-form-model-item label="更新日期"
                           slot="item_2_1"
                           prop="updateDate"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-date-picker style="width: 100%" placeholder="请输入更新日期" v-model="formData.updateDate"/>
        </a-form-model-item>
        <a-form-model-item label="创建日期"
                           slot="item_2_2"
                           prop="createdDate"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-date-picker style="width: 100%" placeholder="请输入创建日期" v-model="formData.createdDate"/>
        </a-form-model-item>
        <a-form-model-item label="描述"
                           slot="item_2_3"
                           prop="desc"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-input placeholder="请输入" v-model="formData.desc"/>
        </a-form-model-item>

        <a-form-model-item label="使用状态_保留"
                           slot="item_1_2_retain"
                           prop="status"
                           :labelCol="{span: 6}"
                           :wrapperCol="{span: 17, offset: 1}">
            <a-select placeholder="请选择" v-model="formData.status">
                <a-select-option value="1">关闭</a-select-option>
                <a-select-option value="2">运行中</a-select-option>
            </a-select>
        </a-form-model-item>

        <a-form-model-item label="更新日期_保留"
                           slot="item_1_1_retain"
                           prop="updateDate"
                           :labelCol="{span: 6}"
                           :wrapperCol="{span: 17, offset: 1}">
            <a-date-picker style="width: 100%" placeholder="请输入更新日期" v-model="formData.updateDate"/>
        </a-form-model-item>

        <a-form-model-item label="规则编号_保留"
                           slot="item_1_3_retain"
                           prop="num"
                           :labelCol="{span: 6}"
                           :wrapperCol="{span: 17, offset: 1}">
            <a-input placeholder="请输入" v-model="formData.num"/>
        </a-form-model-item>
    </g-flexible-conditions-form>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import GFlexibleConditionsForm from '@/components/common/forms/GFlexibleConditionsForm.vue';

@Component({
    name: 'GFlexibleConditionsFormDemo',
    components: { GFlexibleConditionsForm }
})
export default class GFlexibleConditionsFormDemo extends Vue {
    formData = {
        num: 12,
        status: undefined,
        callCount: 0,
        updateDate: undefined,
        createdDate: undefined,
        desc: undefined,
    };

    onSubmit({
                 formDom,
                 value,
             }) {
        alert(JSON.stringify(value));
    }

    onReset(formDom) {
        debugger;
    }
}
</script>

<style scoped lang="less">

</style>
收起状态

展开状态
 优点

布局不用自己操作,只要采用填空的方式(slot:item_{rowIndex}_{colIndex})插入表单组件就行,使用也相对灵

缺点

由于插槽太多,所以需要仔细插入表单组件

方式三

这种方式的使用有个前提,就是条件收缩以后要显示的表单组件,需要连续插入,否则收起的时候组件之间会有空格,而且这个需要使用方式二中的动态插槽,根方式不同的就是收起展开时判断方式的不同。isStrictMode参数必须设置为false,否则无法使用方式三

代码
<!--
 * @description GFlexibleConditionsFormDemo.vue   可伸缩的条件填写表单Demo(方式三)
 * @author JUN - 2023/8/11 9:21
-->
<template>
    <g-flexible-conditions-form :row-count="2" :is-strict-mode="false" :col-count="3" v-model="formData" @submit="onSubmit" @reset="onReset">
        <a-form-model-item label="规则编号"
                           slot="item_1_1"
                           prop="num"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-input placeholder="请输入" v-model="formData.num"/>
        </a-form-model-item>

        <a-form-model-item label="使用状态"
                           slot="item_1_2"
                           prop="status"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-select placeholder="请选择" v-model="formData.status">
                <a-select-option value="1">关闭</a-select-option>
                <a-select-option value="2">运行中</a-select-option>
            </a-select>
        </a-form-model-item>
        <a-form-model-item label="调用次数"
                           slot="item_1_3"
                           prop="callCount"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-input-number style="width: 100%" placeholder="请输入" v-model="formData.callCount"/>
        </a-form-model-item>
        <a-form-model-item label="更新日期"
                           slot="item_2_1"
                           slot-scope="{advanced}"
                           v-if="advanced"
                           prop="updateDate"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-date-picker style="width: 100%" placeholder="请输入更新日期" v-model="formData.updateDate"/>
        </a-form-model-item>
        <a-form-model-item label="创建日期"
                           slot="item_2_2"
                           slot-scope="{advanced}"
                           v-if="advanced"
                           prop="createdDate"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-date-picker style="width: 100%" placeholder="请输入创建日期" v-model="formData.createdDate"/>
        </a-form-model-item>
        <a-form-model-item label="描述"
                           slot="item_2_3"
                           slot-scope="{advanced}"
                           v-if="advanced"
                           prop="desc"
                           :labelCol="{span: 5}"
                           :wrapperCol="{span: 18, offset: 1}">
            <a-input placeholder="请输入" v-model="formData.desc"/>
        </a-form-model-item>
    </g-flexible-conditions-form>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import GFlexibleConditionsForm from '@/components/common/forms/GFlexibleConditionsForm.vue';

@Component({
    name: 'GFlexibleConditionsFormDemo',
    components: { GFlexibleConditionsForm }
})
export default class GFlexibleConditionsFormDemo extends Vue {
    formData = {
        num: 12,
        status: undefined,
        callCount: 0,
        updateDate: undefined,
        createdDate: undefined,
        desc: undefined,
    };

    onSubmit({
                 formDom,
                 value,
             }) {
        alert(JSON.stringify(value));
    }

    onReset(formDom) {
        debugger;
    }
}
</script>

<style scoped lang="less">

</style>
收起状态

展开状态

其实第三种方式使用的是slot-scope(插槽作用域)带有的是否已经展开的表示参数advanced ,作为判断参数进行表单组件的显示与隐藏

小结

其实还有其他的使用方式,可以灵活使用参数配置,解决开发需求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Ant Design of Vue 是一个基于 Vue.js 的 UI 组件库,它提供了丰富的组件和样式,可以帮助开发者快速构建美观、易用的 Web 应用程序。其中,Ant Design of Vue 封装是一个非常实用的功能,它可以帮助开发者快速构建,包括验证、布局、提交等功能,大大提高了开发效率。同时,Ant Design of Vue 封装还支持自定义组件,开发者可以根据自己的需求定制组件,满足不同的业务需求。总之,Ant Design of Vue 封装是一个非常实用的功能,可以帮助开发者快速构建高质量的 Web 应用程序。 ### 回答2: Ant Design of Vue是一个基于Vue.js的UI组件库,它提供了一系列优雅且易用的组件,包含有丰富的UI组件、样式和交互行为,可以帮助我们快速构建漂亮而且功能强大的Web应用。 其中,Ant Design of Vue中最核心、最常用的组件之一,因为是我们在前端开发中最常用的交互方式。Ant Design of Vue中针对封装的功能也非常丰富,主要包括以下几个方面: 1. 控件:Ant Design of Vue提供了一系列的控件,包括输入框、选择器、日期选择器、开关、选框、复选框等,这些控件都有丰富的属性和事件可以自由控制,可以满足我们在不同的场景下的需求。 2. 校验:Ant Design of Vue提供了非常强大的校验功能,可以对进行必填、数据格式、长度等多个方面的校验,还可以自定义校验规则,方便我们在项目中灵活运用。 3. 布局:Ant Design of Vue提供了多种布局,包括水平布局、垂直布局、行内布局等,可以根据不同的需求选择不同的布局方式,在的美观性、可读性等方面都有很好的现。 4. 数据处理:Ant Design of Vue提供了非常便捷的数据处理方式,可以将中的数据进行组装、序列化、反序列化等操作,快捷方便。 总之,Ant Design of Vue提供的封装功能非常丰富、易用,在我们的前端开发中应用广泛,可以大大提高我们的开发效率、代码质量和用户体验。 ### 回答3: Ant Design of Vue 是一个企业级 UI 设计语言和 Vue.js 的实现版本,其中包括了许多常用的组件,如格、、对话框等。 在 Ant Design of Vue 中,是一个非常常用和重要的组件,用于网站的交互和数据处理。Ant Design of Vue 中的组件可以通过简的代码来实现各种元素的布局、样式、校验和提交等功能,同时具有良好的用户体验和可维护性。 Ant Design of Vue封装主要包括三个部分:组件组件和校验规则。 组件Ant Design of Vue 中的一个顶层组件,用于包装整个。通过定义 props 来配置的属性和事件,例如的布局方式、组件的数据和样式绑定、的提交和重置等。 组件中的一个子组件,用于示一个的输入项,如输入框、选框、复选框和下拉框等。通过定义 props 和 v-model 来绑定项和数据,并设置相应的属性和事件来实现校验、关联、联动和交互等功能。 校验规则是 Ant Design of Vue 中用于校验项数据合法性的组件。通过定义 rules 属性来配置校验规则,例如数据格式、数据类型、数据范围和数据比较等。当提交或失焦时,校验规则会自动进行校验,并在校验不通过时提示相应的错误信息。 总体来说,Ant Design of Vue 中的封装具有很高的可用性和可扩展性,能够满足各种不同的业务需求,并且对于前端开发人员来说也十分友好和方便。如果您需要构建一个高品质的企业级,那么 Ant Design of Vue封装一定是您的不二之选。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花姐夫Jun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值