Vue动态表单

326 阅读1分钟

描述

有些时候会碰到一些使用到动态表单的需求,可以动态添加和删除数据,并且对用户输入的数据进行校验。如下图所示:

image.png

实现思路

对于这种需求,可以用table结合form来实现,在外层弄个form,然后form里面嵌套一个table,直接看代码

<template>
  <div class="container">
    <a-row>
      <h1>动态表单demo</h1>
    </a-row>
    <a-form ref="formRef" :model="formData" auto-label-width :rules="rules">
      <a-table :data="formData.data" :pagination="false">
        <template #columns>
          <!-- 姓名 -->
          <a-table-column title="姓名" align="center">
            <template #cell="{ rowIndex, record }">
              <a-form-item :field="`data.${rowIndex}.name`" :rules="rules.name">
                <a-input v-model="record.name" />
              </a-form-item>
            </template>
          </a-table-column>
          <!-- 年龄 -->
          <a-table-column title="年龄" align="center">
            <template #cell="{ rowIndex, record }">
              <a-form-item :field="`data.${rowIndex}.age`" :rules="rules.age">
                <a-input v-model="record.age" />
              </a-form-item>
            </template>
          </a-table-column>
          <!-- 操作 -->
          <a-table-column :width="200" align="center">
            <template #title>
              <a-button type="outline" @click="add">
                <template #icon>
                  <icon-plus />
                </template>
                添加
              </a-button>
            </template>
            <template #cell="{ record, rowIndex }">
              <a-space>
                <a-button type="primary" @click="remove(record, rowIndex)">
                  <template #icon>
                    <icon-delete />
                  </template>
                  删除
                </a-button>
              </a-space>
            </template>
          </a-table-column>
        </template>
      </a-table>
    </a-form>
    <a-row>
      <a-col :span="6" :offset="6">
        <a-button type="primary" @click="submitForm">提交</a-button>
      </a-col>
    </a-row>
  </div>
</template>

<script setup lang="ts">
  import { ref, reactive } from 'vue';
  import { Message } from '@arco-design/web-vue';

  const formRef = ref();

  const genereataData = () => {
    return {
      name: undefined,
      age: undefined,
    };
  };

  const formData = ref({
    data: [genereataData()],
  });
  const rules = reactive({
    name: [
      { required: true, message: '不能为空', trigger: 'blur' },
      { maxLength: 64, message: '长度不能超过64位', trigger: 'blur' },
    ],
    age: [{ required: true, message: '不能为空', trigger: 'blur' }],
  });

  /**
   * 添加一条数据
   */
  const add = () => {
    formData.value.data.push(genereataData());
  };

  /**
   * 删除数据
   * @param record 点击那一行的数据
   * @param rowIndex 行索引
   */
  const remove = (record: any, rowIndex: any) => {
    formData.value.data.splice(rowIndex, 1);
  };

  /**
   * 备用
   * 判读元素是否为空
   * @param obj 元素
   */
  const validatedObjIsNull = (obj: any) => {
    return obj === null || obj === '' || obj === undefined;
  };

  const submitForm = async () => {
    const validated = await formRef.value.validate();
    if (validated) {
      Message.warning('验证失败');
      return;
    }
    Message.success('验证成功');
    // do something
  };
</script>

<style lang="less" scoped>
  .container {
    padding: 15px 20px 0;

    :deep(.arco-card) {
      border-radius: 4px;
    }
  }
</style>

代码下载地址