Vue项目中,如何为遍历生成的form表单设置ref属性

写在前面

  • 在日常开发中,我们常常会通过ref=变量名 的方式获取组件的实例对象;
  • 用得最多的莫过于form表单了,本文基于Vue3+TypeScript+ElementPlus的例子介绍一下为多个表单设置ref属性;

常规用法

  • 对于单个的表单,我们通过ref=属性名的方式就能够轻松获取到表单实例对象,从而使用该对象上的校验表单项的方法,就像下面这样:
  • 自定义变量ruleFormRef赋值给 ref 属性,通过ruleFormRef.value 拿到form表单的实例对象,通过调用validate方法对表单项目进行校验;
    在这里插入图片描述

问题

  • 但是当我们的form表单是动态生成并且存在多个时,这种ref=变量名方式就出问题了;
  • 例如下面的例子,项目可以动态添加多个;但是每个项目的内容是相同的,同时每个项目的必填项都需要填写,这时候我们希望在提交表单的时候通过 validate 方法校验所有项目;于是想当然的和上面例子一样的写法:
    在这里插入图片描述
  • 通过for循环遍历数组,动态生成多个form表单,通过ref拿到表单实例调用validate从而触发表单校验;
  • 但是实际点击提交之后却没有任何反应,断点调试之后发现实例竟是undefined;
    在这里插入图片描述

问题产生原因以及解决方式

  • 其实仔细想问题就出在于我们的表单是for循环动态生成的,但是ref绑定的始终是一个变量,那么当点击提交按钮时;程序也肯定无法判断当前ref绑定的是哪一个form的实例对象;
  • 因此解决关键点就是需要给每一个form表单绑定独立的ref属性,所以ref就不能定义为简单的变量了,需要是一个对象或者数组,用来存储所有表单的实例对象,然后在点击提交按钮时遍历所有的实例对象并且逐个调用validate 方法,从而实现每个表单的独立校验;
  • 那么这里我以数组举例,写法如下:
    在这里插入图片描述
  • 修改之后,我们再进浏览器,点击提交查看效果,从下图可以看到已经正常校验了;
  • 完整代码例子
<template>
  <div style="margin: 20px">
    <el-button type="primary" size="default" @click="handleAdd">新增</el-button>
    <el-button type="primary" @click="submitForm">提交</el-button>
  </div>
  <div v-for="(ruleForm, index) in state.list" :key="index">
    <el-form
      :ref="(el: FormInstance) => (ruleFormRefs[index] = el)"
      :model="ruleForm"
      :rules="rules"
      label-width="120px"
      class="demo-ruleForm"
      :size="formSize"
    >
      <el-form-item label="名称" prop="name">
        <el-input v-model="ruleForm.name" />
      </el-form-item>
      <el-form-item label="地区" prop="region">
        <el-select v-model="ruleForm.region" placeholder="Activity zone">
          <el-option label="Zone one" value="shanghai" />
          <el-option label="Zone two" value="beijing" />
        </el-select>
      </el-form-item>
      <el-form-item label="地区2" prop="count">
        <el-select-v2 v-model="ruleForm.count" placeholder="Activity count" :options="options" />
      </el-form-item>
      <el-form-item label="时间" required>
        <el-col :span="11">
          <el-form-item prop="date1">
            <el-date-picker
              v-model="ruleForm.date1"
              type="date"
              label="Pick a date"
              placeholder="Pick a date"
              style="width: 100%"
            />
          </el-form-item>
        </el-col>
      </el-form-item>
    </el-form>
    <el-divider direction="horizontal" content-position="left"></el-divider>
  </div>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';

interface RuleForm {
  name: string;
  region: string;
  count: string;
  date1: string;
}

const formSize = ref('default');
// const ruleFormRef = ref<FormInstance>();
const ruleFormRefs = ref<FormInstance[]>([]);
const state = reactive<{
  list: RuleForm[];
}>({
  list: [
    {
      name: '',
      region: '',
      count: '',
      date1: '',
    },
  ],
});

const rules = reactive({
  name: [
    { required: true, message: 'Please input Activity name', trigger: 'blur' },
    { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
  ],
  region: [
    {
      required: true,
      message: 'Please select Activity zone',
      trigger: 'change',
    },
  ],
  count: [
    {
      required: true,
      message: 'Please select Activity count',
      trigger: 'change',
    },
  ],
  date1: [
    {
      type: 'date',
      required: true,
      message: 'Please pick a date',
      trigger: 'change',
    },
  ],
});

const handleAdd = () => {
  state.list.push({
    name: '',
    region: '',
    count: '',
    date1: '',
  });
};

const submitForm = async () => {
  ruleFormRefs.value?.forEach((ele) => {
    ele.validate((val) => {
      console.log(val);
    });
  });
  // await ruleFormRef.value?.validate((valid, fields) => {
  //   if (valid) {
  //     console.log('submit!');
  //   } else {
  //     console.log('error submit!', fields);
  //   }
  // });
};

// const resetForm = (formEl: FormInstance | undefined) => {
//   if (!formEl) return;
//   formEl.resetFields();
// };

const options = Array.from({ length: 10000 }).map((_, idx) => ({
  value: `${idx + 1}`,
  label: `${idx + 1}`,
}));
</script>

写在最后

  • 另外值得注意的是,以上例子只是一个简单的测试用例,细节的地方没有过多处理;
  • 如果在实际开发中,这种新增往往伴随着删除,修改等操作;用数组下标作为for循环的key值不可取,应该使用其他唯一标识的字段;同时用于存储form实例的缓存可以定义为对象,通过key-value的形式进行存储,当然如果每个项目的key值刚好是number类型的话,定义成数组就行。
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在使用Vue Element进行列渲染时,可以使用v-for指令遍每个项,并给每个项绑定校验规则。具体步骤如下: 1. 在添加规则属性 在每个添加一个规则属性,用于存放该项的校验规则: ``` <el-form :model="form" :rules="rules" ref="form"> <el-form-item v-for="(item, index) in form.items" :key="index" :label="item.label" :prop="'items.' + index + '.value'" > <el-input v-model="item.value"></el-input> </el-form-item> </el-form> ``` 2. 定义校验规则 在Vue实例定义校验规则,可以使用Element提供的校验规则,也可以自定义校验规则。示例代码如下: ``` data() { return { form: { items: [ { label: '姓名', value: '' }, { label: '年龄', value: '' } ] }, rules: { items: [ { validator: this.validateName, trigger: 'blur' }, { validator: this.validateAge, trigger: 'blur' }, ] } } }, methods: { validateName(rule, value, callback) { if (!value) { callback(new Error('请输入姓名')); } else { callback(); } }, validateAge(rule, value, callback) { if (!value) { callback(new Error('请输入年龄')); } else if (!/^\d+$/.test(value)) { callback(new Error('年龄必须为数字')); } else if (value < 18 || value > 60) { callback(new Error('年龄必须在18-60之间')); } else { callback(); } } } ``` 3. 监听提交事件 在提交按钮的click事件,调用的validate方法进行校验,如果校验通过,执行提交操作: ``` <el-button type="primary" @click="submitForm">提交</el-button> methods: { submitForm() { this.$refs.form.validate(valid => { if (valid) { // 校验通过,执行提交操作 } else { // 校验不通过,弹出错误提示 } }); } } ``` 以上步骤就是在Vue Element并使用校验的基本操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值