antd-vue + vue3 实现a-table动态增减行,通过a-from实现a-table行内输入验证, form嵌套两个table实现检验。

本文介绍了如何在Vue项目中使用ElementUI实现表单和表格的数据同步,并配合验证规则确保数据正确性,以及处理嵌套表单的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

个人博客(vue3 + nodejs + mysql )http://snows-l.site

注意:table的dataSource与form的mode必须是同一个数组
 一、效果图

图一:校验效果

二、主要代码

注意:

1、form 与 table 绑定的是同一个数据 tableSource 并且是一个数据(ElementUI 需要 对象包数组)

2、form用的是 name 绑定  -> :name="[index, 'vlan_id']"

3、form-item 总要需要加上 rules  -> :rules="rules.blur"

<a-form ref="tableFormRef" :model="tableSource" :label-col="{ style: { width: '10px' } }" :wrapper-col="{ span: 0 }" :rules="rules">
  <a-table
    class="ant-table-striped"
    bordered
    :dataSource="tableSource"
    :columns="tableColumns"
    :pagination="false"
    :scroll="{ x: 1260 }"
    :row-class-name="(_record, index) => (index % 2 === 1 ? 'table-striped' : null)">

    <template #bodyCell="{ column, text, record, index }">

      <template v-if="column.dataIndex == 'vlan_id'">
        <a-form-item class="custom-form-item" label=" " :name="[index, 'vlan_id']" :rules="rules.blur">
          <a-input style="width: 100%" v-model:value="record[column.dataIndex]"></a-input>
        </a-form-item>
      </template>

    </template>

  </a-table>
</a-form>

1、template
<div class="bottom-box">
  <div class="title-box">
    <p class="order-title">工单操作</p>
    <a-button style="margin: 0 0 10px 0px" type="primary" size="small" @click="handleRowAdd">增加行</a-button>
  </div>
  <div class="table-box">
    <a-form ref="tableFormRef" :model="tableSource" :label-col="{ style: { width: '10px' } }" :wrapper-col="{ span: 0 }" :rules="rules">
      <a-table
        class="ant-table-striped"
        bordered
        :dataSource="tableSource"
        :columns="tableColumns"
        :pagination="false"
        :scroll="{ x: 1260 }"
        :row-class-name="(_record, index) => (index % 2 === 1 ? 'table-striped' : null)">
        <template #bodyCell="{ column, text, record, index }">
          <template v-if="column.dataIndex == 'vlan_id'">
            <a-form-item class="custom-form-item" label=" " :name="[index, 'vlan_id']" :rules="rules.blur">
              <a-input style="width: 100%" v-model:value="record[column.dataIndex]"></a-input>
            </a-form-item>
          </template>
          <template v-else-if="column.dataIndex == 'cloud'">
            <a-form-item class="custom-form-item" label=" " :name="[index, 'cloud']" :rules="rules.cloud">
              <a-select style="width: 100%" v-model:value="record[column.dataIndex]" @change="hanlePlatformChange(index)">
                <a-select-option v-for="item in platforms" :value="item.value" :key="item.value">{{ item.label }}</a-select-option>
              </a-select>
            </a-form-item>
          </template>
          <template v-else-if="column.dataIndex == 'related_pool'">
            <a-form-item class="custom-form-item" label=" " :name="[index, 'related_pool']" :rules="rules.relatedPool">
              <a-select style="width: 100%" v-model:value="record[column.dataIndex]">
                <a-select-option v-for="item in platform[index].children" :value="item.value" :key="item.value">{{ item.label }}</a-select-option>
              </a-select>
            </a-form-item>
          </template>
          <template v-else-if="column.dataIndex == 'allocated' || column.dataIndex == 'purpose' || column.dataIndex == 'vlan_domain'">
            <a-form-item class="custom-form-item" label=" " :name="[index, column.dataIndex]" :rules="rules.change">
              <a-select style="width: 100%" v-model:value="record[column.dataIndex]">
                <a-select-option v-for="item in column.list" :value="item.value" :key="item.value">{{ item.label }}</a-select-option>
              </a-select>
            </a-form-item>
          </template>
          <template v-else-if="column.dataIndex == 'operation'">
            <a-button style="margin: 0 5px" type="primary" size="small" @click="handleRowDel(index)" danger>删除</a-button>
          </template>
          <template v-else>
            <a-input style="width: 100%" v-model:value="record[column.dataIndex]"></a-input>
          </template>
        </template>
      </a-table>
    </a-form>
  </div>
  <div class="btn-box">
    <a-button v-if="sendFail" style="margin: 0 5px" @click="handleCancleApply">取消申请</a-button>
    <a-button style="margin: 0 5px" type="primary" @click="handleSubmit">提交</a-button>
  </div>
</div>

2、script

<script setup>
import { h, reactive, ref } from 'vue';

// 路由跳转
import { useRouter } from 'vue-router';
const { currentRoute } = useRouter();
const router = useRouter();

const tableFormRef = ref(); // form标签

/**
 *
 * 表格数据
 */
let tableSource = ref([]);

const tableColumns = [
  { title: '序号', dataIndex: 'vlan_id', key: 'vlan_id', align: 'center', width: 65 },
  { title: '所属云平台', dataIndex: 'cloud', key: 'cloud', align: 'center', width: 65 },
  { title: '所属硬件资源池', dataIndex: 'related_pool', key: 'related_pool', align: 'center', width: 65 },
  { title: '类型', dataIndex: 'type', key: 'type', align: 'center', width: 65 },
  { title: '用途', dataIndex: 'purpose', key: 'purpose', align: 'center', width: 65 },
  { title: '规划范围', dataIndex: 'plan', key: 'plan', align: 'center', width: 65 },
  { title: '是否已分配', dataIndex: 'allocated', key: 'allocated', align: 'center', width: 65 },
  { title: '备注', dataIndex: 'remark', key: 'remark', align: 'center', width: 65 },
]

// 校验规则
const rules = {
  blur: [{ required: true, message: '请输入', trigger: 'blur' }],
  change: [{ required: true, message: '请选择', trigger: 'change' }],
  cloud: [{ required: true, message: '请选择所属平台', trigger: 'change' }],
  relatedPool: [{ required: true, message: '请选择硬件资源池', trigger: 'change' }]
};


// 增加行
const handleRowAdd = () => {
  tableSource.value.push({
    vlan_id: null,
    cloud: null,
    related_pool: null,
    type: null,
    purpose: null,
    plan: "",
    allocated: null,
    remark: ""
  });
},

// 删除行
const handleRowDel = (index) => {
  tableSource.value.splice(index, 1)
}
 

// 提交申请
const handleSubmit = () => {
  let params = {};
  if (tableSource.value.length == 0) {
    return message.error('工单不能为空!');
  }

  // form的校验方法
  tableFormRef.value.validate().then(() => {
    const tableSourceParams = JSON.parse(JSON.stringify(tableSource.value));
    params = {
      ...formState, // 其他的参数
      status: 1,
      deviceLists: tableSourceParams
    };
    // 接口
    submitOrder(params).then(res => {
      if (res.code == 8200) {
        cancelId.value = res.data.id;
        if (res.data.status == 3) {
          message.success('二级VLAN地址入网添加成功!');
          router.push({
            path: '/network-access/vlan'
          });
        } else if (res.data.status == 2) {
          message.error(failTip(res.data.errorMessage));
          sendFail.value = true;
          // if (route.query.id) {
          //   echoDate();
          // }
        }
      }
    });
  });
};
</script>

二、form嵌套两个table的情况

因为form与table绑定的值必须是同一个才能就行验证。所以直接form嵌套form就好了

如下图:

这个一样只需要form里面再嵌套form就行了, 不会相互影响的(注意两个form绑定的值不是同的, 所以才需要另一个form来关联里面的table), form与table绑定的值一一对应

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__冬七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值