封装通用el-form表单(2种方式)

news2025/1/18 7:25:48

1、序言

         项目地址:git clone form-demo: 封装通用el-form

        一个后台管理系统最常见的是表单,表单最常见的是输入框、下拉选择、日期选择、单选、复选框等等, 系统添加若干模块,就复制粘贴若干个el-form、el-form-item,有一说一,完成需求快是快,但是代码冗余的部分太多了,能不能通过配置方式,自动生成el-form、el-form-item

        不封装代码前:

        封装代码后:

        两种封装方式的变量、方法名基本一致!

2、自定义组件方式封装el-form

        2.1、封装

        (1)新建commentForm文件夹,并创建index.vue文件

         (2)index.vue中

<template>
  <div>
    <el-form ref="form" :model="form" :rules="rules" :inline="inline" :label-width="labelWidth">
      <template v-for="(item, index) in formItemList">
        <!-- 输入框类型 -->
        <template v-if="item.type === 'input'">
          <el-form-item :label="item.label" :prop="item.model">
            <el-input v-model.trim="form[item.model]" :type="`${item.category || 'text'}`"
              :style="`width: ${item.width || '250px'}`" :clearable="item.clearable === undefined || item.clearable"
              filterable :placeholder="item.placeholder" />
          </el-form-item>
        </template>

        <!-- 下拉选择框 -->
        <template v-if="item.type === 'select'">
          <el-form-item :label="item.label" :prop="item.model">
            <el-select v-model.trim="form[item.model]" :style="`width:${item.width || '250px'}`" clearable
              :placeholder="item.placeholder || ''">
              <el-option v-for="(i, key) in  item.options" :key="i[item.value] || key" :label="i[item.label] || i.label"
                :value="i[item.value] || i.value">
              </el-option>
            </el-select>
          </el-form-item>
        </template>

        <!-- 日期选择器 -->
        <template v-if="item.type === 'date-picker'">
          <el-form-item :prop="item.model" :label="item.label">
            <el-date-picker v-model.trim="form[item.model]" type="daterange" range-separator="至" start-placeholder="开始日期"
              end-placeholder="结束日期">
            </el-date-picker>
          </el-form-item>
        </template>

        <!-- 开关 -->
        <template v-if="item.type === 'switch'">
          <el-form-item :prop="item.model" :label="item.label">
            <el-switch v-model="form[item.model]"></el-switch>
          </el-form-item>
        </template>

        <!-- 复选框 -->
        <template v-if="item.type === 'checkbox'">
          <el-form-item :prop="item.model" :label="item.label">
            <el-checkbox-group v-model="checkboxList">
              <el-checkbox :label="item.label" :key="index" v-for="(item, index) in item.options"></el-checkbox>
            </el-checkbox-group>
          </el-form-item>
        </template>

        <!-- 单选框 -->
        <template v-if="item.type === 'radio'">
          <el-form-item :prop="item.model" :label="item.label">
            <el-radio-group v-model="form[item.model]">
              <el-radio :label="item.label" :key="index" v-for="(item, index) in item.options"></el-radio>
            </el-radio-group>
          </el-form-item>
        </template>

        <!-- 自己拓展... -->
      </template>

      <!-- 按钮列表 -->
      <el-form-item>
        <template v-for="item in buttonList">
          <el-button :type="item.type" @click="item.event">{{ item.text }}</el-button>
        </template>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  props: {
    // 生成el-form-item的数组
    formItemList: {
      type: Array,
      default: () => [],
    },
    // 是否行内表单模式
    inline: {
      type: Boolean,
      default: false,
    },
    // el-form-item的label宽度
    labelWidth: {
      type: String,
      default: '80px',
    },
    // 表单校验规则
    rules: {
      type: Object,
      default: () => { },
    },
    // 按钮列表
    buttonList: {
      type: Array,
      default: () => [],
    }
  },
  data() {
    return {
      form: {},
      checkboxList: [],
    }
  },
  methods: {
    // 返回经过校验的表单
    returnForm() {
      // 将复选框内容添加到form表单中,字段从formItemList type=checkbox中找model
      this.formItemList.forEach(item => {
        if (item.type == 'checkbox') {
          this.form[item.model] = this.checkboxList
        }
      })

      // 表单校验 
      this.$refs['form'].validate((valid) => {
        if (valid) {
          this.$emit('submitForm', this.form)
        }
      })
    },
    // 重置表单
    resetForm() {
      // 重置复选框
      this.checkboxList = []
      this.$refs.form.resetFields();
      this.$emit('resetForm');
    }
  }
}
</script>

<style scoped></style>

        (3)注意事项:

  •  el-checkbox中v-model绑定的值要事先存在,不然就会报出无法找到length属性的错误

            所以提前在data中声明一个数组,v-model绑定这个数组,返回表单给父组件时,将其添加到表单对象中,重置表单时,使这个数组为空即可实现重置表单功能!

  • 重置不成功的原因可能是:(1)未添加prop        (2)prop绑定的值与model绑定的对象所对应的属性不一致

        2.2、使用

重点关注部位:

(1)formItemList中的type决定生成什么类型的表单项,如输入框、下拉选项等等

(2)formItemList中的model表示表单项双向绑定的名称,也是子组件返回对象给父组件中对象的属性名

(3)formItemList中的options表示下拉选项、复选框、单选按钮的选项值

(4)@submitForm绑定的事件可以获取子组件返回给父组件经过校验的表单,通常不在子组件进行网络请求,让父组件进行网络请求

(5)父组件通过$refs获取组件实例从而调用子组件重置表单、提交表单的方法

<template>
  <div id="app">
    <CommonForm ref="form" :rules="rules" :buttonList="buttonList" :formItemList="formItemList" @submitForm="getForm">
    </CommonForm>
  </div>
</template>

<script>
import CommonForm from '@/components/commonForm'
import jsxForm from '@/components/jsxForm';
import JsxForm from '@/components/jsxForm'
export default {
  name: 'App',
  components: {
    CommonForm,
    JsxForm,
    jsxForm
  },
  data() {
    return {
      formItemList: [
        { label: '活动名称', type: 'input', model: 'name', placeholder: '请输入活动名称' },
        { label: '活动区域', type: 'select', model: 'region', placeholder: '请选择状态', options: [{ label: '上海', value: 'shanghai' }, { label: '北京', value: 'beijing' }] },
        { label: '活动时间', type: 'date-picker', model: 'startTime', },
        { label: '即时配送', type: 'switch', model: 'delivery' },
        { label: '活动性质', type: 'checkbox', model: 'type', options: [{ label: '美食/餐厅线上活动' }, { label: '地推活动' }, { label: '线下主题活动' }, { label: '单纯品牌曝光' },] },
        { label: '特殊资源', type: 'radio', model: 'resource', options: [{ label: '线上品牌商赞助' }, { label: '线下场地免费' }] },
      ],
      rules: {
        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
      },
      buttonList: [
        { text: '提交', type: 'primary', event: this.submitForm },
        { text: '重置', event: this.resetForm },
      ]
    }
  },
  methods: {
    // 接受子组件传回来的form表单内容
    getForm(val) {
      console.log('val:', val);
    },
    // 点击提交,触发表单校验
    submitForm() {
      this.$refs.form.returnForm();
    },
    // 重置表单
    resetForm() {
      this.$refs.form.resetForm();
    }
  }
}
</script>

<style>
#app {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #2c3e50;

}
</style>

3、jsx方式封装el-form

jsx封装方式借鉴了这篇文章:element-ui 通用表单封装及VUE JSX应用 - 掘金

        3.1、封装

(1)上篇博客有简单介绍jsx:两种方式对el-table二次封装_码上编程的博客-CSDN博客

(2) 新建jsxForm文件夹,并创建index.js文件

(3)封装代码:

代码逻辑图如下:

export default {
  name: 'jsxForm',
  props: {
    // 生成el-form-item的数组
    formItemList: {
      type: Array,
      default: () => [],
    },
    // 是否行内表单模式
    inline: {
      type: Boolean,
      default: false,
    },
    // el-form-item的label宽度
    labelWidth: {
      type: String,
      default: '100px',
    },
    // 表单校验规则
    rules: {
      type: Object,
      default: () => { },
    },
    // 按钮列表
    buttonList: {
      type: Array,
      default: () => [],
    }
  },
  data() {
    return {
      form: {},
      checkboxList: []
    }
  },
  methods: {
    // 生成选项
    generateOption(itemObj) {
      let options = []
      for (let index = 0; index < itemObj.options.length; index++) {
        const item = itemObj.options[index]
        switch (itemObj.type) {
          // 下拉菜单
          case 'select':
            options.push(<el-option label={item.label} value={item.value}></el-option>)
            break
          // 多选框
          case 'checkbox':
            options.push(<el-checkbox label={item.label}></el-checkbox>)
            break
          // 单选框
          case 'radio':
            options.push(<el-radio label={item.label}>{item.label}</el-radio>)
            break
        }
      }
      return options
    },
    // 生成下拉菜单
    generateSelect(item) {
      return <el-select v-model={this.form[item.model]}>{this.generateOption(item)}</el-select>
    },
    // 生成多选框
    generateCheckbox(item) {
      this.form[item.model] = this.checkboxList
      return <el-checkbox-group v-model={this.checkboxList}>{this.generateOption(item)}</el-checkbox-group>
    },
    // 生成单选
    generateRadio(item) {
      return <div>
        <el-radio-group v-model={this.form[item.model]}>{this.generateOption(item)}</el-radio-group>
      </div>
    },
    // 生成输入框
    generateInput(item) {
      return (<div>
        <el-input v-model={this.form[item.model]} style={{ width: `${this.formItemContentWidth}` }}></el-input>
      </div>)
    },
    // 生成开关
    generateSwitch(item) {
      return <div>
        <el-switch v-model={this.form[item.model]}></el-switch>
      </div>
    },
    // 生成日期组件
    generateDate(item) {
      return <div>
        <el-date-picker v-model={this.form[item.model]} type={"daterange"} range-separator={"至"}
          start-placeholder={"开始日期"} end-placeholder={"结束日期"}>
        </el-date-picker>
      </div >
    },
    // 生成表单项
    generateFormItems(list = []) {
      let formItems = []
      list.forEach(item => {
        let formItemContent = ''
        switch (item.type) {
          // 下拉菜单
          case 'select':
            formItemContent = this.generateSelect(item)
            break
          // 单选框
          case 'radio':
            formItemContent = this.generateRadio(item)
            break
          // 输入框
          case 'input':
            formItemContent = this.generateInput(item)
            break;
          // 开关
          case 'switch':
            formItemContent = this.generateSwitch(item)
            break;
          // 日期
          case 'date-picker':
            formItemContent = this.generateDate(item)
            break;
          // 复选框
          case 'checkbox':
            formItemContent = this.generateCheckbox(item)
            break;
          default:
            break
        }
        formItems.push(<el-form-item label={item.label} prop={item.model}>{formItemContent}</el-form-item>)
      })
      return formItems
    },
    // 按钮列表
    generateBtnList() {
      let buttons = []

      this.buttonList?.forEach(item => {
        buttons.push(<el-button type={item.type} onClick={() => item.event()}>{item.text}</el-button>)
      })
      return buttons
    },
    // 重置表单
    resetForm() {
      // 重置复选框
      this.checkboxList = []
      this.$refs.form.resetFields();
    },

    // 返回经过校验的表单
    returnForm() {
      this.$refs['form'].validate((valid) => {
        if (valid) {
          this.$emit('submitForm', this.form)
        }
      })
    }
  },
  render() {
    return (
      <div>
        <el-form ref="form" props={{ model: this.form }} rules={this.rules} inline={this.inline} label-width={this.labelWidth || '150px'}>
          {this.generateFormItems(this.formItemList)}
          <el-form-item>
            {this.generateBtnList()}
          </el-form-item>
        </el-form>
      </div>
    )
  }
}

        3.2、使用

<template>
  <div id="app">
    <jsxForm ref="form" :buttonList="buttonList" :rules="rules" :formItemList="formItemList" @submitForm="getForm">
    </jsxForm>
  </div>
</template>

<script>
import jsxForm from '@/components/jsxForm';
export default {
  name: 'App',
  components: {
    JsxForm,
  },
  data() {
    return {
      formItemList: [
        { label: '活动名称', type: 'input', model: 'name', placeholder: '请输入活动名称' },
        { label: '活动区域', type: 'select', model: 'region', placeholder: '请选择状态', options: [{ label: '上海', value: 'shanghai' }, { label: '北京', value: 'beijing' }] },
        { label: '活动时间', type: 'date-picker', model: 'startTime', },
        { label: '即时配送', type: 'switch', model: 'delivery' },
        { label: '活动性质', type: 'checkbox', model: 'type', options: [{ label: '美食/餐厅线上活动' }, { label: '地推活动' }, { label: '线下主题活动' }, { label: '单纯品牌曝光' },] },
        { label: '特殊资源', type: 'radio', model: 'resource', options: [{ label: '线上品牌商赞助' }, { label: '线下场地免费' }] },
      ],
      rules: {
        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
      },
      buttonList: [
        { text: '提交', type: 'primary', event: this.submitForm },
        { text: '重置', event: this.resetForm },
      ]
    }
  },
  methods: {
    // 接受子组件传回来的form表单内容
    getForm(val) {
      console.log('val:', val);
    },
    // 点击提交,触发表单校验
    submitForm() {
      this.$refs.form.returnForm();
    },
    // 重置表单
    resetForm() {
      this.$refs.form.resetForm();
    }
  }
}
</script>

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

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

相关文章

Ubuntu下好用的截图工具flameshot

在Linux环境下截图也是十分重要的东西&#xff0c;flameshot则是一款十分好用的工具 sudo apt-get install flameshot 即可安装 安装完成后打开设置(settings) -> 设备(Devices) -> 键盘快捷键(keyboard Shortcuts),滑到最底下&#xff0c;找到一个加号 点击加号填入以…

300块买什么蓝牙耳机好?无线蓝牙耳机300左右推荐

不管你的手机是否被保留3.5mm的音频接口&#xff0c;蓝牙耳机必定是可以入手的&#xff0c;无束缚的听歌方式对我们中的大多数人都有着很强的吸引力。大多数都定价在几十几百几千不等&#xff0c;但是在300左右的价位更受大众欢迎&#xff0c;说明了中端市场是该类产品竞争最激…

如何把Ai绘画工具放到我们的App中

Scribble Diffusion 是一个简单的在线服务&#xff0c;它使用 AI 将粗略的草图转换为精致的图像&#xff0c;每一张图像都是不同的&#xff08;而且没有版权困扰&#xff09;。简单来说&#xff0c;我们只需要「用画笔描绘一张草图&#xff0c;在输入描述后稍等片刻」&#xff…

【Linux】1、操作系统、计算机硬件和软件、Linux 介绍

目录 一、计算机的硬件和软件(1) 硬件(2) 软件 二、操作系统(1) OS 作用(2) OS 举例 三、Linux 内核(1) 介绍(2) Linux 发行版 四、虚拟机 一、计算机的硬件和软件 (1) 硬件 &#x1f5a5;️ 计算机由硬件和软件组成 &#x1f5a5;️ 硬件&#xff1a;计算机中由电子、机械和…

pandas汇总和描述性统计

本文介绍pandas中汇总和描述性统计中的基本内容&#xff0c;仅供参考。 目录 1描述和汇总统计 1.1sum方法 1.2idxmin和idxmax方法 1.3describe方法 1.4描述和汇总统计的常用方法 2相关系数和协方差 3唯一值、值计数以及成员资格 3.1唯一值 3.2值计数 3.3成员资格 1…

【区块链】走进web3的世界-获取Token价格

1、通过预言机获取Token价格&#xff08;需要部署合约&#xff09; 在以太坊区块链上&#xff0c;由于智能合约本身无法获取外部数据&#xff0c;因此需要使用预言机 (Oracle) 来获取外部数据。 以下是一个获取代币价格的示例&#xff1a; 选择预言机&#xff1a;首先需要选…

ThreadLocal小记

1、ThreadLocal介绍 1.1、官方介绍 /*** This class provides thread-local variables. These variables differ from* their normal counterparts in that each thread that accesses one (via its* {code get} or {code set} method) has its own, independently initiali…

PPOCR - 命令行训练模型基本流程和常用命令+visualdl可视化

前言 本文记录实践中用paddleocr训练自己的模型的基本步骤和常用命令&#xff0c;以detection为例 更详细内容请参考官方文档https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.6/doc/doc_ch 〇、环境准备 0.1 paddlepaddle环境安装 paddle环境安装链接 根据自己的…

H.264 编码中, I 帧、B 帧、P 帧、IDR 帧的区别

在H.264协议里定义了三种帧&#xff0c;完整编码的帧叫 I 帧&#xff0c;参考之前的 I 帧生成的只包含差异部分编码的帧叫 P 帧&#xff0c;还有一种参考前后的帧编码的帧叫 B 帧。 H.264采用的核心算法是帧内压缩和帧间压缩&#xff0c;帧内压缩是生成 I 帧的算法&#xff0c…

【镜像取证篇】DD和E01镜像格式区别(简)

【镜像取证篇】DD和E01镜像格式区别&#xff08;简&#xff09; ​ 简单总结下—【蘇小沐】 文章目录 【镜像取证篇】DD和E01镜像格式区别&#xff08;简&#xff09;1、实验环境 &#xff08;一&#xff09;DD镜像-原始镜像&#xff08;和源盘大小一致&#xff09;&#xff0…

C#基础学习--事件

目录 发布者和订阅者 源代码组件概览 声明事件 事件是成员 订阅事件 触发事件 标准事件的用法 通过扩展EventArgs来传递数据 泛型委托 移除事件处理程序 - 事件访问器 发布者和订阅者 发布者/订阅者模式中&#xff0c;发布者类 定义了一系列程序的其他部分可能感兴趣的事件…

第12讲:ElementUI+Vue路由综合案例

本博文主要呈现一个NPM脚手架Vue路由ElementUI的综合案例&#xff0c;完成本案例需要有一定的Vue基础&#xff0c;请参考以下文章完成项目的构建 第08讲&#xff1a;使用脚手架创建vue项目 第09讲&#xff1a;路由开发 第10讲&#xff1a;vue脚手架集成axios 第11讲&#xff1a…

2023年mahorcupC题电商物流网络包裹应急调运与结构思路分析

C 题 电商物流网络包裹应急调运与结构优化问题 电商物流网络由物流场地(接货仓、分拣中心、营业部等)和物流场 地之间的运输线路组成&#xff0c; 如图 1 所示。受节假日和“双十一” 、“618”等促销 活动的影响&#xff0c;电商用户的下单量会发生显著波动&#xff0c;而疫情…

软件测试真的只能干到35岁吗?难道测试岗位真的只是青春饭吗?

一&#xff1a;前言&#xff1a;人生的十字路口静坐反思 入软件测试这一行至今已经10年多&#xff0c;承蒙领导们的照顾与重用&#xff0c;同事的支持与信任&#xff0c;我的职业发展算是相对较好&#xff0c;从入行到各类测试技术岗位&#xff0c;再到测试总监&#xff0c;再…

释放数据价值这道难题,数据科学基础平台有解

去年底&#xff0c;《中共中央、国务院关于构建数据基础制度更好发挥数据要素作用的意见》&#xff08;以下简称&#xff1a;" 数据二十条 "&#xff09;正式颁布&#xff0c;标志着数据基础制度的建设步入快车道&#xff0c;数据要素化有望全面提速。 " 数据二…

通过遍历结果构造二叉树

⭐️前言⭐️ 本篇文章主要总结通过前序遍历、中序遍历、后序遍历中的两个遍历结果&#xff0c;来构造二叉树的过程&#xff0c;通过本篇文章的总结&#xff0c;可以解决一下问题。 LeetCode难度654. 最大二叉树&#x1f7e0;105. 从前序与中序遍历序列构造二叉树&#x1f7e…

编程辅助插件BitoAI使用指南(以VSCode开发环境为例安装并使用BitoAI插件从而提高生产效率)

2023年是AI爆发元年&#xff0c;已经被各种AI工具、新闻轰炸了几个月&#xff0c;只有一种感觉&#xff1a;时间不够用&#xff01; 本文介绍编程辅助神器&#xff1a;Bito AI。 本插件使用与ChatGPT相同的模型&#xff01;目前免费&#xff0c;且拥有强大的辅助能力&#xff0…

高压放大器应用之无损检测

在高压放大器的应用中&#xff0c;很多电子工程师经常会进行无损检测实验&#xff0c;那么无损检测是什么&#xff0c;无损检测的知识又有哪些呢&#xff0c;就让安泰电子带大家来看看。 无损检测是什么&#xff1a; 无损检测是指不损害物品的情况下对产品进行检测的方法&#…

FFMPEG源码分析一 av_register_all()

我们在使用FFMPEG库时&#xff0c;第一个调用的就是av_register_all()&#xff0c;这个函数到底做了什么&#xff0c;有什么用&#xff0c;这里做个简单分析。 本文基于雷霄骅博客学习而来。详情请移步FFmpeg源代码结构图 - 编码_ffmpeg源码结构_雷霄骅的博客-CSDN博客 解析和…

Vsync信号和SurfaceFlinger刷新机制;打造智能车厢的关键技术

概述 车载智能座舱系统在现代汽车中已经越来越常见&#xff0c;它可以提供各种功能&#xff0c;例如音乐、导航和驾驶辅助等。要实现这些功能&#xff0c;需要底层硬件和系统软件的支持。其中&#xff0c;Vsync信号和SurfaceFlinger刷新机制是车载智能座舱系统中的两个关键技术…