首页 > 其他分享 >我是如何使用 vue2+element-ui 处理负责表单,避免单文件过大的问题

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

时间:2024-08-16 14:17:05浏览次数:9  
标签:vue 单项 form 校验 表单 ui vue2 组件 element

引言

在工作中我经常需要处理一些复杂、动态表单,但是随着需求不断迭代,我们也许会发现曾经两三百行的.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 class="line" :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 class="audit-form-item">
    <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文件中。

结语

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

标签:vue,单项,form,校验,表单,ui,vue2,组件,element
From: https://www.cnblogs.com/azoux/p/18362757

相关文章

  • QuickTime Player 在 Mac / iPad / iPhone 上无法播放 .mp4 视频 bug All In One
    QuickTimePlayer在Mac/iPad/iPhone上无法播放.mp4视频bugAllInOneerrors❌从网上下载的.m3u8(有多个.ts格式的视频片段组合成的)MP4视频,使用Mac/iPad/iPhone自带的QuickTimePlayer都无法正常播放视频bug!要么是没有图像,只有声音;要么是只走进度......
  • 界面控件DevExpress .NET MAUI v24.1 - 发布TreeView等新组件
    DevExpress拥有.NET开发需要的所有平台控件,包含600多个UI控件、报表平台、DevExpressDashboardeXpressApp框架、适用于VisualStudio的CodeRush等一系列辅助工具。屡获大奖的软件开发平台DevExpress今年第一个重要版本v23.1正式发布,该版本拥有众多新产品和数十个具有高影响力......
  • 解锁文本奥秘:NSLinguisticTagger在Objective-C中的语言分析之旅
    标题:解锁文本奥秘:NSLinguisticTagger在Objective-C中的语言分析之旅引言在Objective-C的丰富生态中,NSLinguisticTagger扮演着自然语言处理的重要角色。它提供了一套强大的API,用于对文本进行分词和标注,帮助开发者理解文本的结构和含义。本文将深入探讨NSLinguisticTagger的......
  • Vue2 和 Vue3中EventBus使用差异
    目录前言一、EventBus和mitt的对比二、Vue2中的EventBus使用实例2.1创建EventBus2.2在组件中使用EventBus2.2.1组件A-发送事件2.2.2组件B-监听事件2.3注意事项三、Vue3中的mitt使用实例3.1安装mitt3.2创建mitt实例3.3在组件中使用mitt3......
  • 【A GUIDE TO CRC ERROR DETECTION ALGORITHM】 (译文2)
    6.AFullyWorkedExample一个完全可行的例子HavingdefinedCRCarithmetic,wecannowframeaCRCcalculationassimplyadivision,becausethat'sallitis!Thissectionfillsinthedetailsandgivesanexample.定义了CRC算法后,我们现在可以将CRC计算简单地......
  • UiPath发送邮件到指定邮箱有哪些方法技巧?
    UiPath发送邮件到指定邮箱指南?UiPath邮件发送教程?UiPath作为一款功能强大的自动化工具,提供了多种方法和技巧来实现这一需求。AokSend将深入探讨UiPath发送邮件的不同方法和相关技巧,以帮助用户更高效地完成邮件发送任务。UiPath发送邮件:内容附件通过合适的模板和变量,能够让......
  • 【A GUIDE TO CRC ERROR DETECTION ALGORITHM (译文)】上
    AGUIDETOCRCERRORDETECTIONALGORITHM(译文)《APAINLESSGUIDETOCRCERRORDETECTIONALGORITHM》Author:RossN.WilliamsCRC:CyclicRedundancyCheckEverythingyouwantedtoknowaboutCRCalgorithms,butwereafraidtoaskforfearthaterrorsiny......
  • Binance 如何使用 Quickwit 构建 100PB 日志服务(Quickwit 博客)
    三年前,我们开源了Quickwit,一个面向大规模数据集的分布式搜索引擎。我们的目标很宏大:创建一种全新的全文搜索引擎,其成本效率比Elasticsearch高十倍,配置和管理显著更简单,并且能够扩展到PB级别的数据。https://quickwit.io/blog/quickwit-first-release虽然我们知道Quickw......
  • [NSSCTF 2022 Spring Recruit]ezgame
    首先查看本题描述:js分析,源码泄露,信息收集,大致了解了题的解法方向,进入题目页面查看一下,是一个射击游戏,查看源码发现要获得65分才能拿到成绩,一般来说这种游戏基本不可能拿到给定的分数,通常是对源码进行分析然后用bp抓包改包以此来进行分数获得。 结合前面题解的描述,我们先对js文......
  • 040.Vue3入门,在Vue3中引入ElementUI
    1、npminstallelement-plus--save,安装UI 2、main.js代码如下://import'./assets/main.css'//引入下面这两行importElementPlusfrom'element-plus'import'element-plus/dist/index.css'import{createApp}from'vue'importApp......