封装动态表单组件

news2025/1/18 2:00:21

技术栈:vue2+ js + webpack
需求:
利用数据渲染表单,实现代码的精简化及效率的提升。

效果图:
在这里插入图片描述
封装的组件:

  <div v-if="formConfig">
    <el-form
      v-bind="$attrs"
      ref="formDom"
      :model="formData"
      :rules="formRules"
      :inline="inline"
      :label-width="labelWidth"
      :label-position="labelPosition"
    >
      <el-form-item
        v-for="(item, key, index) in formConfig"
        :key="key"
        :label="item.label"
        :label-width="item.labelWidth || '61px'"
        :prop="key"
        :style="item.style"
        v-if="!item.hide"
      >
        <!-- 只列出focus blur change事件举例,更多事件可以自行添加绑定 -->
        <el-input
          v-bind="$attrs"
          v-if="item.type === 'input'"
          v-model="formData[key]"
          :disabled="item.disabled"
          :type="item.inputType ? item.inputType : 'text'"
          :placeholder="item.placeholder || `请输入${item.label}`"
          clearable
          @focus="e => issueEvent(e, item.onFocus)"
          @blur="e => issueEvent(e, item.onBlur)"
          @change="e => issueEvent(e, item.onChange)"
        />

        <el-select
          v-if="item.type === 'select'"
          v-model="formData[key]"
          clearable
          :disabled="item.disabled"
          :placeholder="item.placeholder || `请选择${item.label}`"
          :multiple="item.multiple"
          :filterable="item.filterable"
          :max-tag-count="item.max_tag_count"
          style="width:100%"
          @change="e => issueEvent(e, item.onChange)"
        >
          <el-option
            v-for="list in item.options"
            :key="list.value"
            :value="list.value"
            :label="list.label"
          >
          </el-option>
        </el-select>

        <el-cascader
          v-if="item.type === 'cascader'"
          v-model="formData[key]"
          :disabled="item.disabled"
          :options="item.options"
          :show-all-levels="false"
          style="width:100%"
          :placeholder="item.placeholder || `请输入${item.label}`"
          :props="item.props"
          @change="e => issueEvent(e, item.onChange)"
        ></el-cascader>

        <el-date-picker
          v-if="item.type === 'dateTime'"
          v-model="formData[key]"
          :picker-options="pickerOptions"
          :type="item.dateType ? item.dateType : 'month'"
          :key="item.dateType ? item.dateType : 'month'"
          :placeholder="item.placeholder || `请选择${item.label}`"
          :value-format="item.format"
        ></el-date-picker>
        <slot name="form" :item="item" :from="formData[key]" />
        <div>
          <el-button
            v-if="item.type === 'confirm'"
            type="primary"
            icon="el-icon-search"
            :loading="item.isSearching"
            @click="submit"
          >
            {{ item.text ? item.text : "查询" }}
          </el-button>

          <el-button
            v-if="item.type === 'reset'"
            icon="el-icon-refresh"
            @click="reset"
          >
            {{ item.text ? item.text : "重置" }}
          </el-button>

          <el-button
            v-if="item.type === 'export'"
            class="downloadbtn"
            @click="handleExport"
          >
            <svg-icon icon-class="ic_export" class="tablesvgicon"></svg-icon>
            {{ item.text ? item.text : "导出" }}
          </el-button>
          <slot name="button" :item="item" />
        </div>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  name: "customForm",
  props: {
    // 表单项是否行内显示
    inline: {
      type: Boolean,
      default: true
    },
    // 表单项配置
    formConfig: {
      type: Object,
      default: () => {}
    },
    // 表单项数据
    formDataInit: {
      type: Object,
      default: () => {}
    },
    // 表单标签宽度
    labelWidth: {
      type: [Number, String],
      default: "61"
    },
    // 表单标签位置,默认左侧
    labelPosition: {
      type: String,
      default: "left"
    },
    // 表单校验规则
    formRules: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      formData: this.formDataInit
    };
  },
  methods: {
    //重点在issueEvent函数,可以给事件绑定一个空函数避免报错,如果有外部传入的自定义函数则返回这个函数
    /*组件内函数负责分发表单项事件 */
    issueEvent(value, mouseEvent) {
      if (mouseEvent) {
        return mouseEvent(value);
      }
    },
    submit() {
      this.$emit("submit");
    },
    reset() {
      this.$refs.formDom.resetFields();
      this.$emit("reset");
    },
    handleExport() {
      this.$emit("handleExport");
    }
  }
};
</script>

<style lang="scss" scoped>
/deep/ .el-cascader--medium {
  line-height: 28px;
}
</style>

组件的运用:

<template>
  <div>
    <div class="search-box xl-querybox marginbottom15 borderRadius1 ">
      <!-- 这里是测试页 测试引入组件 -->
      <BaseFrom
        :formDataInit="formDataInit"
        :form-config="formConfig"
        :form-rules="formRules"
        @submit="getList"
      >
        <template #form="{from,item}">
          <div v-if="item.type === 'tab'">
            <el-radio-group v-model="from" @change="handleQuery($event, from)">
              <el-radio-button :label="1">日</el-radio-button>
              <el-radio-button :label="2">月</el-radio-button>
              <el-radio-button :label="3">年</el-radio-button>
            </el-radio-group>
          </div>
        </template>
        <template #button="{item}">
          <div v-if="item.type === 'button'">12313</div>
        </template>
      </BaseFrom>
      <!-- 新增编辑的表单 -->
    </div>
    <div class="edit-from-style">
      <BaseFrom
        :formDataInit="formDataInit"
        :form-config="formConfig2"
        :form-rules="formRules"
        :inline="false"
        @submit="getList"
      >
      </BaseFrom>
    </div>
  </div>
</template>

<script>
import BaseFrom from "@/components/BaseFrom";
import { formatDate_y_m_d } from "@/utils/index";
export default {
  components: {
    BaseFrom
  },
  data() {
    return {
      formConfig2: {
        id: {
          label: "id",
          type: "input",
          // style: { width: "20%" },
          placeholder: "看看提示语",
          labelWidth: "null"
        },
        name: {
          label: "name",
          type: "input",
          placeholder: "看看提示语",
          labelWidth: "null"
        },
        ids: {
          label: "项目id",
          type: "cascader",
          style: { width: "100%" },
          props: {
            expandTrigger: "hover",
            children: "childs",
            label: "label",
            value: "value"
          },
          options: [
            { label: "请选择", value: "" },
            { label: "技术", value: "技术" },
            { label: "生活", value: "生活" },
            { label: "其他", value: "其他" }
          ],
          labelWidth: "null"
        }
      },

      /*----------表格头部的查询表单---------- */
      isSearching: false, // // 是否查询中
      // 表单配置
      formConfig: {
        id: {
          label: "id",
          type: "input",
          placeholder: "看看提示语"
        },
        ids: {
          label: "项目id",
          type: "cascader",
          props: {
            expandTrigger: "hover",
            children: "childs",
            label: "label",
            value: "value"
          },
          options: [
            { label: "请选择", value: "" },
            { label: "技术", value: "技术" },
            { label: "生活", value: "生活" },
            { label: "其他", value: "其他" }
          ]
        },
        status: {
          label: "状态",
          type: "select",
          // multiple: true, // 是否支持多选
          max_tag_count: 1, // 多选时最多显示多少个 tag
          options: [
            {
              label: "数据一",
              value: "0"
            },
            {
              label: "数据二",
              value: "1"
            }
          ],
          onChange: (value, label, arr) => {
            console.log(value, label, arr);
            if (value == "0") {
              this.formConfig["id"].disabled = false;
            } else {
              this.formConfig["id"].disabled = true;
            }
            console.log("this.formDataInit", this.formDataInit);
          }
        },
        tab: {
          label: "周期",
          type: "tab",
          labelWidth: "10"
        },
        time: {
          label: "时间",
          type: "dateTime"
        },
        // time1: {
        //   label: "时间组2件",
        //   type: "dateTime",
        //   dateType: "year",
        //   format: "yyyy-MM-dd",
        //   labelWidth: "100"
        // },
        confirm: {
          text: "查询", // 按钮文案
          type: "confirm",
          label: "     ",
          labelWidth: 0,
          isSearching: this.isSearching
        },
        reset: {
          type: "reset"
        },
        button: {
          type: "button"
        }
      },
      // 表单数据
      formDataInit: {
        id: "",
        page_number: 1,
        page_size: 10,
        time: formatDate_y_m_d(new Date()),
        tab: 1
      },
      // 表单校验规则
      formRules: {
        id: [
          { required: true, message: "请输入id", trigger: "blur" },
          { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
        ],
        status: [{ required: true, message: "请选择", trigger: "change" }]
      }
    };
  },
  methods: {
    getList() {
      console.log("提交了", this.formDataInit);
    },
    handleQuery($event, from) {
      this.formDataInit.tab = from;
      console.log("4444", $event, from);
      switch (from) {
        case 3:
          this.formConfig.time.dateType = "year";
          this.formConfig.time.format = "yyyy-MM-dd";
          this.formConfig.time.placeholder = "选择年";
          break;
        case 2:
          this.formConfig.time.dateType = "month";
          this.formConfig.time.format = "yyyy-MM-dd";
          this.formConfig.time.placeholder = "选择年月";
          break;
        case 1:
          this.formConfig.time.dateType = "date";
          this.formConfig.time.format = "yyyy-MM-dd";
          this.formConfig.time.placeholder = "选择年月日";
          break;

        default:
          break;
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.edit-from-style {
  /deep/.el-form {
    .el-form-item {
      height: 60px;
      line-height: 60px;
      align-items: center;
      text-align: center;
      justify-content: flex-start;
      display: flex;
      border: 1px solid #ebeef5;
      @include timeAndChooseColor2();
      margin-bottom: 0;
      &:not(:last-child) {
        border-bottom: none;
      }
    }
    .el-form-item__content {
      margin-left: 10px !important;
      width: 40%;
      @media screen and (max-width: 800px) {
        width: 66%;
      }
    }
    .el-form-item__label {
      width: 210px;
      line-height: 58px;
      padding-left: 10px;
      background-color: #fafafa;
      border-right: 1px solid #ebeef5;
      &:not(:last-child) {
        border-bottom: none;
      }
      @media screen and (max-width: 800px) {
        width: 90px;
      }
      @include tableBorderColor7();
      @include formBox();
      // @include bgColor2();
    }
  }
}
</style>

参考文章:添加链接描述

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

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

相关文章

为什么你懂英语但不能说流利 学习

目录 对于提升口语流畅度&#xff1a; 我们应该做到是输入和输出占比为3&#xff1a;7&#xff1b;可实际做到的是7&#xff1a;3 但是这个方法也有一个问题&#xff0c;就是没有错误反馈 最好的就是在一个开始的时候&#xff0c;就学对&#xff0c;第一次的效果很重要 另…

vscode中讨厌的蓝色波浪线的去除小trick和原理

问题描述 不小心“设置同步”时和远程电脑的合并&#xff08;merge&#xff09;了&#xff0c;然后就出现了这个问题&#xff01;烦死了&#xff01;&#xff01;&#xff01; 大概是这个样子&#xff1a; 解决办法 站在了巨人的肩膀上&#xff0c;在下图位置输入这样一行参数&…

【TCP】四次挥手(最强详解!!通俗易懂!!)

目录 想要了解三次握手的话可以参考我的另外一篇博客 首先来了解一下FIN和ACK FIN ACK 接着我们再来具体的了解TCP四次挥手过程 转换为最最通俗理解方法: 想要了解三次握手的话可以参考我的另外一篇博客 【TCP】三次握手&#xff08;最强详解&#xff01;&#xff01;通俗…

DVWA XSS

反射型 low 查看源代码&#xff0c;没有任何过滤 构造 medium 这里是过滤了 high 这里把双写和大小写和JavaScript都过滤了,用事件来绕过<img src0 οnerrοralert(“xss”)> impossible 这里使用htmlspecialchars进行实体转换并且输出的结果还不能使用事件来…

HarmonyOS/OpenHarmony(Stage模型)应用开发单一手势(一)

一、点击手势&#xff08;TapGesture&#xff09; TapGesture(value?:{count?:number; fingers?:number}) 点击手势支持单次点击和多次点击&#xff0c;拥有两个可选参数&#xff1a; count&#xff1a;非必填参数&#xff0c;声明该点击手势识别的连续点击次数。默认值为…

Python Qt学习(七)Listview

源代码&#xff1a; # -*- coding: utf-8 -*-# Form implementation generated from reading ui file qt_listview.ui # # Created by: PyQt5 UI code generator 5.15.9 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not…

数据库设计DDL

DDL&#xff1a;数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库、表&#xff09; DDL&#xff08;数据库操作&#xff09; 查询&#xff1a; 查询所有数据库&#xff1a;show databases; 查询当前数据库&#xff1a;select database(); 使用&#xff1a; 使用…

前端实习第七周周记

前言 第六周没写&#xff0c;是因为第六周的前两天在处理第五周的样本库部分。问题解决一个是嵌套问题&#xff08;因为我用到了递归&#xff09;&#xff0c;还有一个问题在于本机没有问题&#xff0c;打包上线接口404。这个问题我会在这周的总结中说。 第六周第三天才谈好新…

RT-Thread 线程管理(二)

系统线程 系统线程是指由系统创建的线程&#xff0c;用户线程是由用户程序调用线程管理接口创建的线程&#xff0c;在 RT-Thread 内核中的系统线程有空闲线程和主线程。 空闲线程 空闲线程&#xff08;idle&#xff09;是系统创建的最低优先级的线程&#xff0c;线程状态永远…

解决D盘的类型不是基本,而是动态的问题

一、正确的图片 1.1图片 1.2本人遇到的问题 二、将动态磁盘 转为基本盘 2.1 基本概念&#xff0c;动态无法转化为基本&#xff0c;不是双向的&#xff0c;借助软件 网址&#xff1a;转换动态磁盘到普通磁盘_检测到计算机本地磁盘为动态分区_卫水金波的博客-CSDN博客 2.2分区…

每日一题 2240. 买钢笔和铅笔的方案数

难度&#xff1a;中等 枚举就行 class Solution:def waysToBuyPensPencils(self, total: int, cost1: int, cost2: int) -> int:res 0for i in range(total//cost1 1):res (total - i * cost1) // cost2res 1return res

高等数学啃书汇总重难点(四)不定积分

本章主要考察方法性的技巧&#xff0c;对于某些理论性的概念&#xff0c;建议在练习中加强理解&#xff0c;不定积分的要义在于不断练习、不断拓宽眼界 一.不定积分的概念 二.原函数存在定理 三.不定积分的定义 四.基本积分表 五.不定积分的性质 六.一类换元法 七.二类换元法 八…

phpstorm配置链接sqlserver数据库

开启sqlserver的TCP/IP 1433端口

硬件性能评估指标-DMIPS、MFLOPS、MAC、TOPS

硬件性能评估指标-DMIPS、MFLOPS、MAC、TOPS DMIPS&#xff08;Dhrystone Million Instructions Per Second&#xff09;&#xff1a; DMIPS用于衡量计算机系统的整体指令执行性能&#xff0c;通常关注整数操作。它基于Dhrystone基准测试来计算&#xff0c;该测试主要包含整数运…

如何利用好 IntelliJ IDEA 的调试功能辅助代码调试

文章目录 调试的重要性配置断点启动调试利用 IntelliJ IDEA 的调试功能观察变量和表达式单步执行和逐级跳转查看调用栈条件断点监视变量远程调试使用断点条件和日志 调试最佳实践总结 &#x1f389;欢迎来到Java学习路线专栏~如何利用好 IntelliJ IDEA 的调试功能辅助代码调试 …

YOLOv8超参数调优教程! 使用Ray Tune进行高效的超参数调优!

原创文章为博主个人所有,未经授权不得转载、摘编、倒卖、洗稿或利用其它方式使用上述作品。违反上述声明者,本站将追求其相关法律责任。 这篇博文带大家玩点新的东西,也是一直以来困扰大家最大的问题—超参数调优! 之前的 YOLOv5 我使用遗传算法做过很多次调优,实验一跑就…

实战项目 在线学院之集成springsecurity

一 操作配置 1.0 工程结构 1.1 在common下创建spring_security模块 1.2 pom文件中依赖的注入 1.3 在service_acl模块服务中引入spring-security权限认证模块 1.3.1 service_acl引入spring-security 1.3.2 在service_acl编写查询数据库信息 定义userDetailServiceImpl 查询用…

day08-领取优惠券(高并发优化:超卖、锁失效、事务边界、事务失效)

由于优惠券的发放数量限制、每人限领数量限制&#xff0c;因此在领取优惠券的过程中必须判断优惠券的库存以及当前用户的领取数量。也就是避免出现超发现象&#xff0c;这跟电商中的库存超卖是处理是类似的。 通过今天的学习&#xff0c;希望大家可以达成下列目标&#xff1a;…

【网络教程】群晖如何正确的安装openwrt旁路由

文章目录 准备安装导入镜像创建虚拟机访问旁路由旁路由网络设置准备 我这里的环境是群晖DSM7.2版本首先大家需要预先安装套件Virtual Machine Manager,这里就省略了 根据个人需求去下载openwrt的固件,下载的时候选择x86的img镜像文件,这里也可以直接使用我使用的这个固件(资…