首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

我是如何使用 vue2+element-ui 处理负责表单,避免单文件过大的问题

编程知识
2024年08月16日 13:19

引言

在工作中我经常需要处理一些复杂、动态表单,但是随着需求不断迭代,我们也许会发现曾经两三百行的.vue文件现在不知不觉到了两千行,三千行,甚至更多...

这对于一个需要长期维护的项目,无疑是增加了很多难度。

因此,为了减小文件大小,优化表单组织的结构,我在日常的开发中实践出一种基于组件的表单拆分方法,同时还能保证所有的表单项是处于同一个el-form中。

这对于一个一开始就没有做好文件组织,组件化的项目,有以下几个优点:

  1. 改动小!后续新增表单项基本不会改动以前的代码
  2. 基于组件!在逻辑上对表单项做出拆分,并在任何地方嵌入
  3. 易维护!化单个大组件为多个小组件,每个组件只专注于一部分表单。

表单拆分

接下来我们会通过完成一个实际表单的方式来介绍如何实践这种表单组织方式。

element-ui文档中的这个表单为例,接下来尝试用我们的方式来实现

首先假设我们当前有一个vue文件 ./form/myForm.vue

<template>
  <el-form ref="form" :model="form" label-width="140px">
  ...
  </el-form>
<template>
<script>
export default {
 name: 'myForm',
 data() {
  return {
   form: {}
  }
 }
}
</script>

如果我们直接按照element-ui的表单文档来写,那么我们的myForm.vue文件可能就会变成这样:

<el-form ref="form" :model="form" label-width="80px">
  <el-form-item label="活动名称">
    <el-input v-model="form.name"></el-input>
  </el-form-item>
  <el-form-item label="活动区域">
    <el-select v-model="form.region" placeholder="请选择活动区域">
      <el-option label="区域一" value="shanghai"></el-option>
      <el-option label="区域二" value="beijing"></el-option>
    </el-select>
  </el-form-item>
  <el-form-item label="活动时间">
    <el-col :span="11">
      <el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
    </el-col>
    <el-col :span="2">-</el-col>
    <el-col :span="11">
      <el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
    </el-col>
  </el-form-item>
  <el-form-item label="即时配送">
    <el-switch v-model="form.delivery"></el-switch>
  </el-form-item>
  <el-form-item label="活动性质">
    <el-checkbox-group v-model="form.type">
      <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
      <el-checkbox label="地推活动" name="type"></el-checkbox>
      <el-checkbox label="线下主题活动" name="type"></el-checkbox>
      <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
    </el-checkbox-group>
  </el-form-item>
  <el-form-item label="特殊资源">
    <el-radio-group v-model="form.resource">
      <el-radio label="线上品牌商赞助"></el-radio>
      <el-radio label="线下场地免费"></el-radio>
    </el-radio-group>
  </el-form-item>
  <el-form-item label="活动形式">
    <el-input type="textarea" v-model="form.desc"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">立即创建</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>
<script>
  export default {
    data() {
      return {
        form: {
          name: '',
          region: '',
          date1: '',
          date2: '',
          delivery: false,
          type: [],
          resource: '',
          desc: ''
        }
      }
    },
    methods: {
      onSubmit() {
        console.log('submit!');
      }
    }
  }
</script>

假设我们还需要为这个表单增加审批流程,例如文档中的这个表单
在加入新的表单项后,可能目前看着还好,但是随着表单项越来越多,这个文件会变得越来越大,越来越难以维护。所以我们尝试将这个表单项拆分为单个组件,模拟我们维护一个超大表单的场景。

新增子表单项组件

我习惯在当前表单的目录下,创建一个components目录,然后在components目录下创建一个audit目录,并在audit目录下创建一个index.vue文件,用于存放审批流程相关的组件。如果后续有一些只有audit/index.vue文件中才用到的组件,我也会放在audit目录下。保持目录结构清晰。

<template>
  <div>
    <el-form-item label="审批人" :prop="`${propPrefix}.user`">
      <el-input v-model="form.user" placeholder="审批人"></el-input>
    </el-form-item>
    <el-form-item label="活动区域" :prop="`${propPrefix}.region`">
      <el-select v-model="form.region" placeholder="活动区域">
        <el-option label="区域一" value="shanghai"></el-option>
        <el-option label="区域二" value="beijing"></el-option>
      </el-select>
    </el-form-item>
  </div>
</template>
<script>
export const auditFormData = () => ({
  user: '',
  region: ''
})

export default {
 name: 'auditFormItem',
 props: {
  value: {
   type: Object,
   default: () => auditFormData()
  },
  propPrefix: {
   type: String,
   default: ''
  }
 },
 data() {
  return {
   form: this.value
  }
 },
 watch: {
  value(newVal) {
   this.form = newVal
  },
  form(newVal) {
   this.$emit('input', newVal)
  }
 }
}
</script>

因为element-ui在对表单进行校验时,实际上是对model上绑定的数据进行校验,所以为了能够对数据正确执行校验,我们需要在auditFormItem组件中实现v-model指令。

auditFormItem组件的propPrefix属性用于指定表单项的前缀,便于我们在嵌入到el-form中时,能够正确绑定表单项的prop属性。

auditFormData函数返回了当前表单项的默认数据。父组件通过执行该函数,可以对子表单执行正确的初始化。不仅如此,通过这种方式,我们将每个子表单项的数据和组件绑定在一起,避免了父组件data中出现大量表单项数据,导致难以维护的问题。每个子表单维护各自的数据,互不干扰。

如何嵌入已有项目

接下来我们尝试将auditFormItem组件嵌入到myForm.vue文件中

<template>
  <el-form ref="form" :model="form" label-width="140px">
    <!-- 其他表单项 -->
    <!-- ... -->
    <audit-form-item v-model="form.audit" propPrefix="audit"></audit-form-item>
  </el-form>
</template>
<script>
import auditFormItem, { auditFormData } from './components/audit/index.vue'
export default {
  components: {
    auditFormItem
  },
  data() {
    return {
      form: {
        audit: auditFormData()
      }
    }
  }
}
</script>

如何进行校验

经过上面的操作,我们实现了将一个表单拆分为多个子表单项,那么如何进行表单校验呢?

我们知道在element-ui中,要对一个表单项进行校验有两种方式:

一种是在el-form上绑定rules属性,它会通过prop进行索引,自动对绑定的表单项进行校验。
另一种是在el-form-item上绑定rules属性,这会对单条表单项进行校验。

出于我们拆分表单项的场景,我们选择第二种方式,在el-form-item上绑定rules属性,然后在各个子组件中维护rules。如果有一些通用的校验规则,我们也可以在audit/validate.js文件中进行维护,然后通过import的方式引入。

如何处理联动校验

在复杂表单中,我们可能需要对多个表单项进行联动校验,例如:实时校验表单项的合法性,当form.regionshanghai时,form.user不能为空,当form.regionbeijing时,form.user必须为空。

那么如何处理这种联动校验呢?

我们可以在el-form所在的组件中,定义一个validate方法,通过element-ui提供的validateField方法,对特定进行校验。

<audit-form-item v-model="form.audit" propPrefix="audit" @validate="validate"></audit-form-item>

methods: {
  validate(fields) {
    this.$refs.form.validateField(fields)
  }
}

然后在audit/index.vue文件中,我们可以通过$emit('validate', fields)方法,对当前表单项进行校验。

如何处理跨组件的联动校验

在我们拆分表单为多个子组件后,还可能会出现不同子组件之间的联动校验,例如:当子组件1中的form.regionshanghai时,子组件2中的form.user不能为空。
对于这个问题,其实我目前还没有想到很好的解决方案,当前是在el-form所在的组件中,定义额外的校验规则,然后绑定到一个空白的el-form-item上。

<el-form-item label="" label-width="0" prop="_form_validate_"></el-form-item>

rules: {
  _form_validate_: {
    validator: (rule, value, callback) => {
      // 联动校验逻辑
    }
  }
}

也可以考虑用vuex来维护需要跨组件共享的数据。

const crossCmpConfig = {
  state: {
    region: '',
  },
  mutations: {
    UPDATE: (state, { key, val }) => {
      state[key] = val
    },
  },
}

export default crossCmpConfig

多层嵌套

基于上面的方式,很容易就能想到,我们甚至可以继续在audit/index.vue文件中,继续嵌入别的子组件,例如:audit/audit-info/index.vue, 然后通过相同的方式,继续嵌入到audit/index.vue文件中。

结语

上面就是我日常开发中,处理复杂表单的一些经验总结,希望对大家有所帮助。

From:https://www.cnblogs.com/azoux/p/18362757
本文地址: http://shuzixingkong.net/article/1157
0评论
提交 加载更多评论
其他文章 AvaloniaChat:一个基于大语言模型用于翻译的简单应用
简介 一个使用大型语言模型进行翻译的简单应用。 A simple application using a large language model for translation. 使用指南 访问GitHub地址:https://github.com/Ming-jiayou/AvaloniaChat
AvaloniaChat:一个基于大语言模型用于翻译的简单应用 AvaloniaChat:一个基于大语言模型用于翻译的简单应用 AvaloniaChat:一个基于大语言模型用于翻译的简单应用
如何判断数据库和对象存储是否被 JuiceFS 使用?
随着使用 JuiceFS 的时间越来越长,一些用户已经用多种数据库和对象存储创建了很多的 JuiceFS 文件系统。有些是纯云端的,有些是纯本地的,有些则是本地与云端结合的。它们当中有一些是存储了文件的,而有一些则只是测试目的临时创建的。多个文件系统混合在一起使用难免会混淆,特别是在同一个数据库实例
如何判断数据库和对象存储是否被 JuiceFS 使用? 如何判断数据库和对象存储是否被 JuiceFS 使用? 如何判断数据库和对象存储是否被 JuiceFS 使用?
如何做一个优雅的提问者
最近加了很多新人朋友,大部分都是初级开发者。都想要加入开发者群交流讨论平时遇到的问题。新人朋友有这种想法其实蛮好的,但是很多人似乎都不知道如何有效提出自己的问题,他们往往一张图或者一句话就往群里一扔,并且希望能有群友给自己解答。 大部分情况这种问题都会石沉大海,少部分情况下会有一些热心肠的群友会指出
如何做一个优雅的提问者 如何做一个优雅的提问者 如何做一个优雅的提问者
免杀基础学习记录
前言 参考SecretTeam安全团队的学习记录 什么是免杀? 免杀(Bypass AV, Anti-Virus Evasion)是指恶意软件通过各种手段规避杀毒软件和安全检测系统的识别和拦截,从而在目标系统中成功执行。这种技术不仅用于恶意软件的传播,也被信息安全研究人员用来测试和提升安全防护系统的
免杀基础学习记录 免杀基础学习记录
2024 暑假记
说明 本篇文章用于记录暑假每天的作息、安排、收获和经历。 \(2024 - 06 - 24\) 会考啦,在郑州市创新实验中学考点 \(52\) 考场 \(17\) 号。 第一场生物,考完后去操场休息了会,见到挺多认识的同学,还见到了很久没联系的小学同学,差点没认出来。 第二场地理,挺简单的,基本都是
2024 暑假记 2024 暑假记 2024 暑假记
reduce() 多种用法
reduce()方法用于将数组简化为单一值,通过遍历数组并应用提供的函数。它可以用于求和、乘积、计算对象属性的总和、数组去重和转换数组结构等。初始值的设置会影响reduce的起始索引。不提供初始值时,从索引1开始执行;提供初始值则从索引0开始。 一、 定义和用法reduce() 方法将数组缩减为单个
mysql8.0 主从架构模式【0到1架构系列】
前提条件 准备3,4,5台虚拟机 祼装mysql8.0 主从架构 常见两种模式“一主多从”和“级联复制”两种,基本都很简单,都是依赖binlog日志文件进行同步,binlog日志会记录DDL和部分DDL语句,进行同步时从库会重新执行这些语句从而实现主从同步。 步骤1: 配置主/从服务器的server
mysql8.0 主从架构模式【0到1架构系列】 mysql8.0 主从架构模式【0到1架构系列】 mysql8.0 主从架构模式【0到1架构系列】
别再被坑了! JavaScript类型检测的最佳实践
别再被坑了! JavaScript类型检测的最佳实践 在 JavaScript 中,我们经常需要判断一个变量的类型。这个需求在编程中非常常见,因为不同类型的数据会影响到我们的代码逻辑。 JavaScript 提供了几种方法来检测数据类型,每种方法都有自己的优缺点。 Object.prototype.
别再被坑了! JavaScript类型检测的最佳实践