el-form简单封装一个列表页中的搜索栏

news2024/11/15 20:05:32

父组件如何使用    代码中注释很多, 应该很容易理解

<template>
    <div>
        <wgySearch
            v-model="searchDefault"
            :fields="searchFields"
            @reset="reset"
            @submit="submit"
        >
            <!-- 通过 slot 自定义的组件  传啥都行 -->
            <template slot="delivery">
                <el-switch v-model="searchDefault.delivery" />
            </template>
        </wgySearch>

    </div>
</template>


<script>
import wgySearch from './wgySearch';

// 这两个组件是给search组件传递的
import wgySelect from './wgySelect';
import wgyDatePicker from './wgyDatePicker';

            data 中
            // 搜索栏中的默认值
            searchDefault: {
                name: '',
                region: '',
                delivery: '',
                date: '',
            },
            // 配置项
            searchFields: [
                {
                    label: '活动名称',
                    model: 'name',
                },
                {
                    label: '活动区域',
                    model: 'region',
                    template: {
                        // tpl传一个wgySelect组件,专门用来只用来传数据
                        tpl: wgySelect,
                        attrs: {
                            multiple: true,
                            list: [
                                { label: 'A', value: 1 },
                                { label: 'B', value: 2 },
                            ],
                        },
                    },
                },
                {
                    label: '即时配送',
                    slot: 'delivery',  // 这里配置项是slot, 模板中才能使用slot对应的字段
                },
                {
                    label: '活动时间',
                    model: 'date',
                    template: {
                        tpl: wgyDatePicker,
                        attrs: {
                            type: 'daterange',
                            'value-format': 'timestamp',
                        },
                    },
                },
            ],


        reset和submit这两方法是搜索和重置的时候调用的
</script>

wgySelect组件

<template>
    <el-select
        v-model="value1"
        v-bind="$attrs"
        @input="input"
    >
        <el-option
            v-for="item in list"
            :key="item.value"
            :label="item.label"
            :value="item.value"
        />
    </el-select>
</template>
<script>
export default {
    name: 'WgySelect',

    props: {
        value: {
            type: [Number, String, Array],
            required: true,
        },
        list: {
            type: Array,
            required: true,
        },
    },
    data() {
        return {
            value1: this.value,
        };
    },
    methods: {
        input(val) {
            this.$emit('input', val);
        },
    },
};
</script>

wgyDatePicker组件

<template>
    <el-date-picker
        v-model="value1"
        range-separator="至"
        start-placeholder="开始日期"
        v-bind="$attrs"
        end-placeholder="结束日期"
        @input="input"
    />
</template>

<script>
export default {
    name: 'WgyDatepicker',

    props: {
        value: {
            type: [Array, Number, String],
            default: () => '',
        },
    },
    data() {
        return {
            value1: this.value,
        };
    },
    methods: {
        input(val) {
            this.$emit('input', val || '');
        },
    },
};
</script>

wgySearch 这个就是最主要的搜索组件了

<template>
    <div>
        <!-- 如果插槽  operatorLeft 或 operatorRight 存在则展示顶部区域 -->
        <div
            v-if="$slots.operatorLeft || $slots.operatorRight"
            class="slot-operator clearfix"
        >
            <div class="pull-left">
                <slot name="operatorLeft"></slot><!-- 表单的左上方区域  -->
            </div>
            <div class="pull-right">
                <slot name="operatorRight"></slot><!-- 表单的右上方区域 -->
            </div>
        </div>

        <div class="form-ctn">
            <el-form
                :ref="formAttrs.ref || 'form'"
                :model="formData"
                :inline="true"
                :label-width="getLabelWidth"
                label-position="right"
                v-bind="formAttrs"
                size="small"
                @submit.native.prevent="submit"
                @reset.native.prevent="reset"
            >
                <div :style="getWrapperStyle">
                    <el-form-item
                        v-for="(field, index) in innerFields"
                        :key="`${field.model || field.slot}${index}`"
                        :prop="field.prop"
                        :label="field.label"
                        :rules="field.rules"
                        :style="{display: (index + 1) > maxShowNum && !showAll ? 'none' : 'inline-block'}"
                    >
                        <!-- 如果有telplate可能是复杂类型,比如日期,下拉框等 -->
                        <wgy-template
                            v-if="field.template"
                            v-model="formData[field.model]"
                            :tpl="field.template.tpl"
                            :style="{width: `${getTempWidth(field.template.attrs)}px`}"
                            :attrs="field.template.attrs"
                            v-on="field.template.events"
                        />
                        <!-- 没有telplate的话,就是输入框input -->
                        <!-- -->
                        <template v-else>
                            <!--
                                如果input是个插槽,就展示插槽,否则展示自己的input
                                绑定当前配置的model
                                透传itemAttrs
                            -->
                            <slot
                                v-if="field.slot"
                                :name="field.slot"
                            ></slot>
                            <el-input
                                v-else
                                v-model.trim="formData[field.model]"
                                :placeholder="field.placeholder"
                                clearable
                                class="w180"
                                v-bind="field.itemAttrs"
                            />
                        </template>
                    </el-form-item>
                    <slot name="suffixCustomitems"></slot>
                    <div
                        :class="btnClass"
                        :style="getBtnStyle"
                    >
                        <el-button
                            v-if="fields.length > maxShowNum"
                            type="text"
                            @click="showAll = !showAll"
                        >
                            <i :class="showAll ? 'el-icon-caret-top' : 'el-icon-caret-bottom'"></i>
                            {{ showAll ? '收起' : '展开' }}
                        </el-button>
                        <el-button
                            v-if="showSubmit"
                            type="primary"
                            native-type="submit"
                            class="search-btn"
                        >
                            {{ leftButton }}
                        </el-button>
                        <el-button
                            v-if="showReset"
                            native-type="reset"
                            class="reset-btn"
                        >
                            {{ rightButton }}
                        </el-button>
                        <span class="ml10">
                            <slot name="searchbtn"></slot>
                        </span>
                    </div>
                </div>
            </el-form>
        </div>

        <div
            v-if="withDivider"
            class="divider"
        ></div>
    </div>
</template>

<script>
import wgyTemplate from './wgyTemplate';

export default {
    components: {
        wgyTemplate,
    },
    props: {
        // 绑定的值
        value: {
            type: Object,
            required: true,
        },
        leftButton: {
            type: String,
            default: () => '查询',
        },
        rightButton: {
            type: String,
            default: () => '重置',
        },
        // 每行元素个数
        lineNumber: {
            type: Number,
            default: () => 4,
        },
        // label 的宽度
        labelWidth: {
            type: String,
            default: () => '100px',
        },
        // 透传给el-form的属性配置
        formAttrs: {
            type: Object,
            default: () => ({}),
            required: false,
        },
        // 配置字段
        fields: {
            type: Array,
            required: true,
        },
        // 是否显示搜索按钮
        showSubmit: {
            type: Boolean,
            default: true,
        },
        // 是否显示重置按钮
        showReset: {
            type: Boolean,
            default: true,
        },
        // 最大默认显示搜索项个数 ,超过这个数字后会收起
        maxShowNum: {
            type: Number,
            default: 8,
        },
        // 按钮组class
        btnClass: {
            type: String,
            default: '',
        },
        // 自动包含下方的分割线(列表页常用)
        withDivider: {
            type: Boolean,
            default: true,
        },
    },
    data() {
        return {
            // 绑定的值
            formData: this.value,
            // 配置字段 < 默认显示搜索项个数
            showAll: this.fields.length < this.maxShowNum,
        };
    },
    computed: {
        // 处理placeholder
        innerFields() {
            return this.fields.map((field) => {
                const { template, label } = field;
                // 根据是否有template属性,生成默认的placeholder
                const defaultPlaceholder = template ? `请选择${label}` : `请输入${label}`;

                if (template) {
                    // 如果有template属性,但没有attrs属性,初始化attrs为一个空对象
                    template.attrs = template.attrs || {};
                    // 如果attrs对象没有placeholder属性,使用默认的placeholder
                    template.attrs.placeholder = template.attrs.placeholder || defaultPlaceholder;
                } else {
                    // 如果没有template属性,且没有placeholder属性,使用默认的placeholder
                    field.placeholder = field.placeholder || defaultPlaceholder;
                }
                return field;
            });
        },
        getWrapperStyle() {
            // 动态改变该元素的布局
            return {
                display: 'flex',
                flexWrap: 'wrap',
            };
        },
        getIsSameLine() {
            // 判断表单的字段数量是否小于等于每行的元素个数并且字段数量不能被每行的元素个数整除
            const { fields, lineNumber } = this;
            return fields.length <= lineNumber && !(fields.length % lineNumber === 0);
        },
        // 按钮的样式
        getBtnStyle() {
            return {
                textAlign: this.getIsSameLine ? 'left' : 'right',
                flex: 1,
                minWidth: '220px',
                marginBottom: '10px',
            };
        },
        /**
         * 计算表单标签的宽度
         * 如果用户已经设置了 labelWidth,则直接返回用户设置的值
         * 否则,根据表单字段的标签长度动态计算标签宽度
         */
        getLabelWidth() {
            if (this.labelWidth) {
                return this.labelWidth;
            }
            // 获取表单字段标签的最大长度
            const maxLength = Math.max(...this.fields.map((item) => item.label.length));
            if (maxLength <= 4) {
                return '80px';
            }
            if (maxLength > 4 && maxLength <= 6) {
                return '90px';
            }
            if (maxLength > 6 && maxLength < 10) {
                return '120px';
            }
            return '100px';
        },
        validate() {
            return this.$refs.form.validate;
        },
    },
    watch: {
        // 外层变化实时通知内部, 内部变化实时通知外部
        value: {
            deep: true,
            handler(newVal) {
                this.formData = newVal;
            },
        },
        formData: {
            deep: true,
            handler(newVal) {
                this.$emit('input', newVal);
            },
        },
    },
    methods: {
        // 搜索
        submit() {
            this.$emit('submit');
        },
        // 重置
        reset() {
            this.$emit('reset');
        },
        /*
            获取每个输入框的宽度
            如果attrs中有传入, 使用传入的宽度
            如果是日期选择器,宽度是210
            如果是日期时间选择器,宽度是340
            其他的宽度都是180
        */
        getTempWidth(attrs = {}) {
            const { width, type } = attrs;
            if (width) {
                return width;
            }
            if (type === 'daterange') {
                return 210;
            }
            if (type === 'datetimerange') {
                return 340;
            }
            return 180;
        },
    },
};
</script>

<style lang="scss">
.search-box {
    background: #fff;
    .slot-operator {
        border-bottom: 1px solid #eee;
        padding-bottom: 10px;
        margin-bottom: 10px;
    }
    .form-ctn {
        position: relative;
        .search-btn,
        .reset-btn {
            min-width: 0;
        }
        .reset-btn {
            margin-left: 8px;
        }
    }
    .el-form-item {
        margin-bottom: 16px;
        white-space: nowrap;
    }
    .el-form-item--small .el-form-item__label {
        padding-right: 5px;
    }
    .el-form-item--small .el-form-item__content {
        min-width: 180px;
        .el-date-editor--daterange .el-range-input {
            min-width: 70px;
        }
    }
}
.divider {
    box-sizing: border-box;
    background-color: #fafafb;
    height: 10px;
    border-top: 1px solid #eeeeee;
    border-bottom: 1px solid #eeeeee;
}
</style>

wgyTemplate  是wgySearch组件中的子组件

<template>
    <component
        :is="dynamicComponent"
        :value="value"
        v-bind="attrs"
        v-on="listeners"
    />
</template>

<script>

export default {
    name: 'WgyTemplate',
    props: {
        tpl: {
            type: [String, Object],
            required: true,
        },
        value: {
            type: [Number, String, Object, Array],
            required: true,
        },
        attrs: {
            type: Object,
            default: () => ({}),
        },
    },
    computed: {
        // 要渲染的组件
        dynamicComponent() {
            return this.tpl;
        },
        // 收集所有需要绑定到动态组件上的事件监听器
        listeners() {
            return {
                input: this.input,
                ...this.$listeners,
            };
        },
    },
    methods: {
        input(value) {
            this.$emit('input', value);
        },
    },
};
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1078808.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

段码屏学习

文章目录 1.液晶屏和OLED屏2.液晶屏原理3.码段屏原理4.单色点阵屏原理5.彩色点阵屏原理6.HT1621驱动LCD段码屏 1.液晶屏和OLED屏 答&#xff1a; 液晶屏&#xff1a;码段屏、单色点阵屏、彩色点阵屏。 OLED屏&#xff1a;消费类电子产品多&#xff0c;贵。 2.液晶屏原理 …

三相智能电表逆相序的原因及解决方法

随着电力系统的快速发展&#xff0c;智能电表已逐渐替代传统电表&#xff0c;成为我国电力系统的重要组成部分。在众多类型的智能电表中&#xff0c;三相智能电表以其高精度、稳定性和智能化程度&#xff0c;被广泛应用于工商业及居民用电领域。然而&#xff0c;在使用过程中&a…

许战海战略文库|主品牌老化:企业增长面临的关键挑战

在今天&#xff0c;大部分行业的竞争环境已经从匀速变化迭代为加速变化&#xff0c;主品牌老化成为企业增 长面临的重要挑战&#xff0c;这一点已经变得非常明显。技术革新、产业革命以及顾客需求的演变势不 可挡&#xff0c;跨周期竞争已经成为常态。在这种情况下&#xff0c;…

传统但是很简单的计算Renko大小方法,FPmarkets1分钟分享

Renko图表是一种经典的技术分析工具&#xff0c;其计算方法较为传统。交易者通常需要手动设置以点数表示的常量值来确定Renko砖块的大小。 今天FPmarkets1分钟分享&#xff0c;传统但是很简单的计算Renko大小方法&#xff0c;不用指标&#xff0c;就可以使用Excel电子表格来计…

北京怎么开股票账户?哪家证券公司股票开户佣金最低?

北京怎么开股票账户&#xff1f;哪家证券公司股票开户佣金最低&#xff1f; 开设股票账户可以去证券营业部或者线上找客户经理进行开户具体步骤如下&#xff1a; 准备好本人有效身份证明证件&#xff08;如居民身份证、护照等&#xff09;及银行卡。 填写开户申请表&#xff…

亚马逊,速卖通,敦煌产品测评补单攻略:低成本、高安全实操指南

随着电商平台的发展和消费者对产品质量的要求提升&#xff0c;测评补单成为了商家们提升销售和用户口碑的关键环节。然而&#xff0c;如何在保持成本低廉的同时确保操作安全&#xff0c;一直是卖家们面临的挑战。今天林哥分享一些实用的技巧和策略&#xff0c;帮助卖家们产品的…

docker 安装 neo4j

1. 安装所需的软件包 yum install -y yum-utils device-mapper-persistent-data lvm2 2. 设置阿里云仓库(国内仓库稳定) yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3. 查看docker容器版本 yum list docker-ce --showdupl…

小白看得懂的 Transformer (图解)

来源&#xff1a;Python数据科学 来源&#xff1a;Python数据科学本文约7200字&#xff0c;建议阅读14分钟在本文中&#xff0c;我们将研究Transformer模型&#xff0c;理解它的工作原理。1.导语 谷歌推出的BERT模型在11项NLP任务中夺得SOTA结果&#xff0c;引爆了整个NLP界。…

低代码自动翻页采集山姆商品数据

1 前言 山姆超市以会员经营为主&#xff0c;会员需要向商家购买会员卡才可以获得购物权&#xff0c;享受更多的优惠和折扣&#xff0c;这种模式实际上是通过高质量的商品和服务吸引顾客忠诚度&#xff0c;建立"忠诚顾客"的经营模式。山姆超市的商品销售以大批次和整箱…

401-视频与网络应用篇-网络分层和常见网络协议

常使用的网络有广域网&#xff08;WAN&#xff09;、城域网、局域网&#xff08;LAN&#xff09;&#xff0c;一般我们遇到的场景是广域网和局域网&#xff0c;广域网就是常说的外网&#xff0c;而局域网一般用于学校、公司等场合。在家庭路由器中对应WAN口和LAN口。网络是极为…

学生宿舍智能电表改造解决方案

随着科技的发展和人们对环保意识的提高&#xff0c;节能减排已经成为当今社会的重要议题。学生宿舍作为学生生活、学习的重要场所&#xff0c;其能源消耗问题日益受到关注。为了提高学生宿舍的能源利用效率&#xff0c;降低能源消耗&#xff0c;智能电表改造成为了一种有效的解…

3、字符设备驱动框架和开发步骤

一、Linux内核对文件的分类 Linux的文件种类 1、-&#xff1a;普通文件2、d&#xff1a;目录文件3、p&#xff1a;管道文件4、s&#xff1a;本地socket文件5、l&#xff1a;链接文件6、c&#xff1a;字符设备7、b&#xff1a;块设备 Linux内核按驱动程序实现模型框架的不同&…

深图SONTU医用X射线高压发生器维修SONTU-HFG50

X射线高压发生器的高压开不起来常见故障分析&#xff1a; 这是X射线荧光光谱仪较常见的故障&#xff0c;一般发生在开机时&#xff0c;偶尔也发生在仪器运行中。故障的产生原因可以从三个方面去分析&#xff1a;1、X射线防护系统;2、内部水冷系统;3、高压发生器及X射线光管。 …

离散傅里叶变换(DFT)的推导及C语言实现

1、傅里叶变换&#xff08;FT&#xff09; 傅里叶变换&#xff08;连续时间傅里叶变换&#xff09;是该部分内容的理论基础&#xff0c;回顾一下&#xff1a; 傅里叶变换&#xff1a; 傅里叶逆变换&#xff1a; 以上是连续时间傅里叶变换&#xff0c;但计算机只能处理离散的数…

practical on mifare

抽象的。 mifare Classic 是市场上使用最广泛的非接触式智能卡。 其设计和实施细节由制造商保密。 本文研究了该卡的体系结构以及卡与读卡器之间的通信协议。 然后&#xff0c;它提供了一种实用的、低成本的攻击&#xff0c;可以从卡的内存中恢复秘密信息。 由于伪随机生成器的…

计算32位二进制整数中1的个数(包括负数补码)

引言&#xff1a; 在计算机科学和编程中&#xff0c;位操作是一项重要的技能。一个常见的任务是计算一个32位二进制整数中1的个数&#xff0c;包括负数的补码表示。这个问题有多种解决方法&#xff0c;本博客将介绍一种高效的解决方案&#xff0c;同时提供详细的代码案例。 背…

“优化STM32单片机处理大量网络数据的方法“

"优化STM32单片机处理大量网络数据的方法" 在处理大量网络数据时&#xff0c;对STM32单片机的裸机程序&#xff0c;可采用以下处理方法&#xff1a;1.使用DMA实现直接内存访问&#xff0c;减轻CPU负担。2.优化缓冲区管理&#xff0c;使用循环缓冲区或多缓冲区。3.利…

智能垃圾桶在线监测方案

提高垃圾收集率、减少乱丢垃圾是我们共同努力的目标&#xff0c;在人口稠密的城市&#xff0c;垃圾是必要的服务&#xff0c;在许多城市&#xff0c;垃圾车是空的&#xff0c;垃圾随处可见沿线&#xff0c;但它不是有效的方法&#xff0c;因为有很多空间可以很多垃圾离开的路上…

Java Agent之ByteBuddy

1&#xff1a;前言 在上一篇文章介绍 Java Agent 技术时&#xff0c;结合 Byte Buddy 技术实现了统计方法执行时间的功能。本次分享深入介绍 Byte Buddy 的一些基础知识&#xff0c;SkyWalking Agent 强大的地方就是重度使用该工具实现探针数据动态生成代码填充参数的。 2&am…

基于springboot实现在线动漫信息交流分享平台项目【项目源码+论文说明】

基于springboot实现在线动漫信息交流分享平台演示 摘要 随着社会互联网技术的快速发展&#xff0c;每个行业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于在线动漫信息平台当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xf…