前端分页:非当前页进行表单验证

概览

对于大数据量批量导入,渲染到表格的场景中,可能会造成浏览器崩溃,此时前端分页可以很好地解决这个问题,但是组件库自带的表单验证通常只能进行当前页的验证,如何实现对全量数据的表单验证呢?此篇文章来梳理解决

一. 完整代码示例

<template>
  <el-form :model="dataForm" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    <table border>
      <thead>
        <tr>
          <th>#</th>
          <th><span class="requiredLabel">姓名</span></th>
          <th><span class="requiredLabel">年龄</span></th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item, index) in currentPageData" :key="index">
          <td>{{ index + (currentPage - 1) * pageSize + 1 }}</td>
          <td>
            <el-form-item
              :prop="'details.' + (index + (currentPage - 1) * pageSize) + '.name'"
              :rules="rules.name"
              :key="'details.' + (index + (currentPage - 1) * pageSize) + '.name'"
            >
              <el-input
                v-model="item.name"
                placeholder="请输入姓名"
                clearable
              ></el-input>
            </el-form-item>
          </td>
          <td>
            <el-form-item
              :prop="'details.' + (index + (currentPage - 1) * pageSize) + '.age'"
              :rules="rules.age"
              :key="'details.' + (index + (currentPage - 1) * pageSize) + '.age'"
            >
              <el-input
                v-model="item.age"
                placeholder="请输入年龄"
                clearable
                type="number"
              ></el-input>
            </el-form-item>
          </td>
        </tr>
      </tbody>
    </table>
    <div>
      <el-button @click="prevPage" :disabled="currentPage === 1">上一页</el-button>
      <el-button @click="nextPage" :disabled="currentPage === Math.ceil(totalCount / pageSize)"
        >下一页</el-button
      >
    </div>
    <el-button @click="handleCreate">立即创建</el-button>
  </el-form>
</template>

<script setup>
  import { reactive, ref, computed,nextTick } from 'vue';
  import AsyncValidator from 'async-validator';

  const dataForm = reactive({
    details: Array.from({ length: 20 }, (_, i) => ({ name: '', age: null })),
  });

  const rules = {
    name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
    age: [{ required: true, message: '请输入年龄', trigger: 'blur'}],
  };

  const currentPage = ref(1);
  const pageSize = ref(5);
  const totalCount = ref(dataForm.details.length);
  const ruleForm = ref(null);

  const currentPageData = computed(() => {
    const start = (currentPage.value - 1) * pageSize.value;
    const end = start + pageSize.value;
    return dataForm.details.slice(start, end);
  });

  const schemaValidator = (item) => {
    const schema = new AsyncValidator(rules);
    return schema
      .validate(item, { firstFields: true })
      .then((res) => {
        console.log(res, 'then res');
        return true;
      })
      .catch(({ errors }) => {
        return false;
      });
  };

  const handleCreate = async () => {
    const fields = {
      name: {
        rules,
        validate: schemaValidator,
      },
    };
    for (let i = 1; i < dataForm.details.length; i++) {
      const item = dataForm.details[i];
      let allValid = true; // 假设当前 item 的所有字段都有效
      for (const key in item) {
        if (fields[key]) {
          try {
            if (!(await fields[key].validate(item))) {
              currentPage.value = Math.floor((i+1)/pageSize.value) + 1;
              allValid = false;
              break; // 跳出内层循环
            }
          } catch (error) {
            allValid = false;
            break; // 跳出内层循环,并在发生错误时也视为验证失败
          }
        }
      }
      if (!allValid) {
        break; // 跳出外层循环
      }
    }
    await nextTick();
    ruleForm.value.validate((valid) => {
      console.log(valid,'valid123456')
      if (valid) {
        console.log('表单验证通过');
        // 处理表单提交逻辑
      } else {
        console.log('表单验证失败');
        return false;
      }
    });
  };

  const prevPage = () => {
    if (currentPage.value > 1) currentPage.value--;
  };

  const nextPage = () => {
    if (currentPage.value < Math.ceil(totalCount.value / pageSize.value)) currentPage.value++;
  };
</script>

<style lang="scss" scoped>
  /* 添加您的样式 */
</style>

可以直观运行感受下

二. 解决思路梳理

整体实现思路:

  1. 校验时,获取第一个不符合校验项的下标;
  2. 根据下标,找到对应不符合项的页码;
  3. 切换当前页码至不符合项的页码;
  4. 进行表单验证

此时的难点在于如何获取不符合项的页码

需要借助async-validator库的使用,这里着重讲下,相关代码如下

  import AsyncValidator from 'async-validator';
  const rules = {
    name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
    age: [{ required: true, message: '请输入年龄', trigger: 'blur'}],
  };
  const schemaValidator = (item) => {
    const schema = new AsyncValidator(rules);
    return schema
      .validate(item, { firstFields: true })
      .then((res) => {
        console.log(res, 'then res');
        return true;
      })
      .catch(({ errors }) => {
        return false;
      });
  };
 const handleCreate = async () => {
    const fields = {
      name: {
        rules,
        validate: schemaValidator,
      },
    };
    for (let i = 1; i < dataForm.details.length; i++) {
      const item = dataForm.details[i];
      let allValid = true; // 假设当前 item 的所有字段都有效
      for (const key in item) {
        if (fields[key]) {
          try {
            if (!(await fields[key].validate(item))) {
              currentPage.value = Math.floor((i+1)/pageSize.value) + 1;
              allValid = false;
              break; // 跳出内层循环
            }
          } catch (error) {
            allValid = false;
            break; // 跳出内层循环,并在发生错误时也视为验证失败
          }
        }
      }
      if (!allValid) {
        break; // 跳出外层循环
      }
    }
    await nextTick();
    ruleForm.value.validate((valid) => {
      if (valid) {
        console.log('表单验证通过');
        // 处理表单提交逻辑
      } else {
        console.log('表单验证失败');
        return false;
      }
    });
  };

需要进行两层的循环遍历,第一层是全部的数据,第二层是校验规则,在全部的数据里面根据校验规则进行筛选,主要如下

  1. 遍历全部数据,根据校验规则,获取到全部数据中子项中有校验的字段;
  2. 调用validate进行校验,获取全部数据中子项中第一个不符合校验的下标值;

async-validator的作用主要是什么?

可以根据校验规则,来进行是否符合校验判断,并返回布尔值。

三. 循环中退出

有两种写法:
第一种:增加变量,break退出

const getWrapperInnerData = async () => {
  for (let i = 0; i < propsDetails.length; i++) {
    const item = propsDetails[i];
    let valid = true;
    for (const key in item) {
      if (fields[key]) {
        if (!(await validateName(item.index).catch(() => false))) {
          console.log(item.index);
          valid = false;
          break;
        }
      }
    }
    if (!valid) {
      break;
    }
  }
};

第二种:return 退出

const getWrapperInnerData = async () => {
  for (let i = 0; i < propsDetails.length; i++) {
    const item = propsDetails[i];
    for (const key in item) {
      if (fields[key]) {
        if (!(await validateName(item.index).catch(() => false))) {
          console.log(item.index);
          return false;
        }
      }
    }
  }
};

第一种写法

在第一种写法中,通过引入一个valid变量来跟踪当前项的校验状态,并在发现不符合项时通过break语句退出内层循环。然后,在外层循环中检查valid变量的值,如果为false,则通过另一个break语句退出外层循环。这种方式需要额外的变量和嵌套的控制流语句来管理循环的退出。

第二种写法

第二种写法则更为直接。在内层循环中,一旦发现不符合校验项,就立即通过return false语句退出整个函数。这种方式省去了额外的变量和复杂的控制流结构,使得代码更加简洁明了。同时,由于return语句会立即终止函数的执行,因此也确保了函数在找到第一个不符合项后不会继续处理剩余的项。

此外,第二种写法还隐含了一个优势:它清晰地表达了函数的意图——即校验过程中一旦发现不符合项就立即终止,并返回一个表示失败的值(在这里是false)。这种明确的返回值使得函数的调用者能够更容易地理解函数的执行结果。

因此,从简洁性和明确性的角度来看,第二种写法是更优的选择。它不仅能够实现所需的功能,而且代码更加清晰易懂。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PVE定时开启关闭虚拟机,实现PVE中群晖虚拟机的定时开机和关闭

如果在PVE中安装了群晖&#xff0c;又不想每天关闭PVE(不在家&#xff0c;怕服务器起不来)&#xff0c;因此想每天定时关闭开启黑群晖和其他虚拟机释放资源。 在网上查了很多&#xff0c;说在crontab添加命令 00 2 * * * pvesh create /nodes/pve/qemu/102/status/stop 00 6 …

JDBC/ODBC—数据库连接API概述

JDBC/ODBC概述 在数据库连接领域&#xff0c;有两种广泛使用的技术&#xff1a;ODBC&#xff08;Open Database Connectivity - 开放数据库连接&#xff09;和 JDBC&#xff08;Java Database Connectivity - Java 数据库连接&#xff09;。 一、什么是 ODBC&#xff1f; Ope…

2024年NSSCTF秋季招新赛-WEB

The Beginning F12看源码&#xff0c;有flag http标头 黑吗喽 题目说要在发售时的0点0分&#xff0c;所以添加标头data Date: Tue, 20 Aug 2024 00:00:00 GMT然后改浏览器头 User-Agent: BlackMonkey曲奇就是Cookie cookieBlackMonkey这个一般就是Referer Referer:wukon…

后台管理系统的通用权限解决方案(十一)SpringBoot的统一异常处理

文章目录 1 统一异常处理介绍2 统一异常处理案例 1 统一异常处理介绍 在实际项目中&#xff0c;不可避免需要处理各种异常。如果每个都单独处理&#xff0c;代码中则会出现大量的try {...} catch {...} finally {...}代码块&#xff0c;不仅有大量的冗余代码&#xff0c;而且还…

Axure使用动态面板制作新闻栏目高级交互

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;使用动态面板制作新闻栏目 主要内容&#xff1a;动态面板State切换、控制&#xff1b;动态面板滚动设置&#xff1b;设置选中 应用场景&#xff1a…

android数组控件Textview

说明&#xff1a;android循环控件&#xff0c;注册和显示内容 效果图&#xff1a; step1: E:\projectgood\resget\demozz\IosDialogDemo-main\app\src\main\java\com\example\iosdialogdemo\TimerActivity.java package com.example.iosdialogdemo;import android.os.Bundl…

2024年10月文章一览

2024年10月编程人总共更新了21篇文章&#xff1a; 1.2024年9月文章一览 2.《Programming from the Ground Up》阅读笔记&#xff1a;p147-p180 3.《Programming from the Ground Up》阅读笔记&#xff1a;p181-p216 4.《Programming from the Ground Up》阅读笔记&#xff…

List 列表基础用法

List 列表基础用法 列表可以完成大多数集合类的数据结构实现。列表中元素的类型可以不相同&#xff0c;它支持数字&#xff0c;字符串甚至可以包含列表&#xff08;所谓嵌套&#xff09;。 列表是写在方括号 [] 之间、用逗号分隔开的元素列表。 和字符串一样&#xff0c;列表…

企业如何通过架构蓝图实现数字化转型

数字化转型的关键——架构蓝图的力量 在当今的商业世界&#xff0c;数字化转型已经不再是一个选择&#xff0c;而是企业生存与发展不可回避的战略行动。企业希望通过数字化提高效率、增强灵活性&#xff0c;并为客户提供更好的体验。然而&#xff0c;数字化转型不仅仅涉及技术…

数字马力二面面试总结

24.03.07数字马力二面面试总结 前段时间找工作,做的一些面试笔记总结 大家有面试录音或者记录的也可以发给我,我来整理答案呀 数字马力二面面试总结 24.03.07数字马力二面面试总结你可以挑一个你的最有挑战性的,有难度的,最具有复杂性的项目,可以简单说一下。有没有和算…

了解SQLExpress数据库

SQLExpress&#xff08;Microsoft SQL Server Express&#xff09;是由微软公司开发的一款免费且轻量级的数据库管理系统。以下是关于SQLExpress的详细解释&#xff1a; 一、定义与特点 定义&#xff1a; SQLExpress是Microsoft SQL Server的一个缩减版或基础版&#xff0c;旨在…

华为荣耀曲面屏手机下面空白部分设置颜色的方法

荣耀部分机型下面有一块空白区域&#xff0c;如下图红框部分 设置这部分的颜色需要在themes.xml里面设置navigationBarColor属性 <item name"android:navigationBarColor">android:color/white</item>

服务器数据恢复—SAN环境中LUN映射错误导致文件系统一致性出错的数据恢复案例

服务器数据恢复环境&#xff1a; SAN光纤网络环境&#xff0c;存储由一组6块硬盘组建的RAID6阵列构成&#xff0c;划分为若干LUN&#xff0c;MAP到跑不同业务的SUN SOLARIS操作系统服务器上。 服务器故障&分析&#xff1a; 因为业务需要&#xff0c;用户在该光纤存储环境中…

【python】OpenCV—Connected Components

文章目录 1、任务描述2、代码实现3、完整代码4、结果展示5、涉及到的库函数6、参考 1、任务描述 基于 python opencv 的连通分量标记和分析函数&#xff0c;分割车牌中的数字、号码、分隔符 cv2.connectedComponentscv2.connectedComponentsWithStatscv2.connectedComponents…

【LangChain系列4】【Chain模块详解】

目录 前言一、LangChain1-1、介绍1-2、LangChain抽象出来的核心模块1-3、特点1-4、langchain解决的一些行业痛点1-5、安装 二、Chain模块2-1、介绍2-2、LLMChain2-3、Sequential Chain&#xff08;顺序链&#xff09;2-4、Router Chain 总结 前言 LangChain给自身的定位是&…

[pdf,epub]105页《分析模式》漫谈合集01

105页的《分析模式》漫谈合集第1集的pdf、epub文件&#xff0c;已上传到本账号的CSDN资源。 如果无法下载&#xff0c;也可以访问umlchina.com/url/ap.html 已排版成适合手机阅读&#xff0c;pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》&#xff1f; ★[缝合故…

Python酷库之旅-第三方库Pandas(186)

目录 一、用法精讲 861、pandas.Index.names属性 861-1、语法 861-2、参数 861-3、功能 861-4、返回值 861-5、说明 861-6、用法 861-6-1、数据准备 861-6-2、代码示例 861-6-3、结果输出 862、pandas.Index.nbytes属性 862-1、语法 862-2、参数 862-3、功能 8…

rabbitmq高级特性(2)TTL、死信/延迟队列、事务与消息分发

目录 1.TTL 1.1.设置消息过期时间 1.2.设置队列过期时间 2.死信队列 2.1.介绍 2.2.演示 3.延迟队列 3.1.模拟实现延迟队列 3.2.延迟队列插件 4.事务与消息分发 4.1.事务 4.2.消息分发 1.TTL 所谓的ttl&#xff0c;就是过期时间。对于rabbitmq&#xff0c;可以设置…

el-table type=“selection“换页多选数据丢失的解决办法

element里有一个 reserve-selection属性 设置以后就可以保留之前选中的选项&#xff0c;但还要设置row-key 代码如下&#xff1a; <el-tableref"mytable":data"HostRows"borderv-loading"loading"element-loading-text"正在加载中...&q…

Gitee push 文件

1、背景 想将自己的plecs仿真放到git中管理&#xff0c;以防丢失&#xff0c;以防乱改之后丢失之前版本仿真。此操作说明默认用户已下载git。 2、操作步骤 2.1 开启Git Bash 在文件夹中右键&#xff0c;开启Git Bash。 2.2 克隆文件 在Git Bash中打git clone git地址&#…