Use v-for in vue to realize two nested loops, judge whether a sub-element is displayed, and perform complex form validation

1. Demand scenario:

There is the following usage scenario, the name 111, name 222, and name 333 are placed in a large array, and then displayed through the first layer of for loop. The name 333 array contains its own sub-array, and the sub-array is displayed through the second for loop. When we choose the distribution method, those that meet the selection criteria will only display the first-time ratio corresponding to that row. Finally, form validation is performed on each item in the sub-array.
insert image description here
Regarding the array structure, we can customize it on the front end.

const form = reactive({
    
    
  title: '',
  templateList: [{
    
    
    key: 'region',
    label: '名称111',
    list: [{
    
     settlement_type: '1', limit_days: '0', rate: '', settlement_way: '' }]
  }, {
    
    
    key: 'partner',
    label: '名称222',
    list: [{
    
     settlement_type: '2', limit_days: '0', rate: '', settlement_way: '' }]
  }, {
    
    
    key: 'user',
    label: '名称333',
    list: [
      {
    
     settlement_type: '3', limit_days: '30', rate: '', settlement_way: '' },
      {
    
     settlement_type: '3', limit_days: '60', rate: '', settlement_way: '' },
      {
    
     settlement_type: '3', limit_days: '180', rate: '', settlement_way: '' },
      {
    
     settlement_type: '3', limit_days: '90', rate: '', settlement_way: '' },
    ]
  }]
})

2. Solution:

You can consider using to v-forperform double-layer nested loops, and there are several points to note:

1. The index in the parent loop must be distinguished from the index in the sub-loop when writing, so as not to confuse them.
2. Do not omit the :key value. The parent loop corresponds to the index of the parent, and the child loop corresponds to the index of the child.

3. Code implementation:

<template>
<!-- ========= 这是循环取出第一层数组,保存在item里面 ======== -->
  <div
        v-for="(item,index) in form.templateList"
        :key="index"
      >
        <div style="margin-bottom:10px;">
          {
   
   { item.label }}
        </div>
        <!-- ========= 这是循环出第二层数组,注意要在item里面取出 ======== -->
        <a-row
          :gutter="15"
          v-for="(itemChild,indexChild) in item.list"
          :key="indexChild"
        >
          <a-col :span="8">
            <a-form-item
              :field="`templateList[${index}].list[${indexChild}].rate`"
              :label="Number(itemChild.limit_days) > 0 ? itemChild.limit_days + '天利息':'利息'"
              :rules="formRules.rate"
            >
              <a-input
                v-model="itemChild.rate"
                placeholder="请填写"
                allow-clear
              >
                <template #append>
                  %
                </template>
              </a-input>
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item
              :field="`templateList[${index}].list[${indexChild}].settlement_way`"
              label="发放方式"
              :rules="formRules.settlement_way"
            >
              <a-select
                v-model="itemChild.settlement_way"
                placeholder="请选择"
                allow-clear
                @change="((val) => {
                  changeSelect(val,itemChild)
                })"
              >
                <a-option
                  v-for="item in giveModelList"
                  :key="item.key"
                  :label="item.val"
                  :value="item.key"
                />
              </a-select>
            </a-form-item>
          </a-col>
          <a-col
            :span="8"
            v-if="itemChild.settlement_way === '3'"
          >
            <a-form-item
              :field="`templateList[${index}].list[${indexChild}].first_rate`"
              label="首发比例"
              :rules="formRules.first_rate"
            >
              <a-input
                v-model="itemChild.first_rate"
                placeholder="请填写"
                allow-clear
              >
                <template #append>
                  %
                </template>
              </a-input>
            </a-form-item>
          </a-col>
        </a-row>
      </div>
</template>

<script setup lang="ts">
import {
      
       ref, unref, reactive, onMounted } from "vue"
const form = reactive({
      
      
  title: '',
  templateList: [{
      
      
    key: 'region',
    label: '名称111',
    list: [{
      
       settlement_type: '1', limit_days: '0', rate: '', settlement_way: '' }]
  }, {
      
      
    key: 'partner',
    label: '名称222',
    list: [{
      
       settlement_type: '2', limit_days: '0', rate: '', settlement_way: '' }]
  }, {
      
      
    key: 'user',
    label: '名称333',
    list: [
      {
      
       settlement_type: '3', limit_days: '30', rate: '', settlement_way: '' },
      {
      
       settlement_type: '3', limit_days: '60', rate: '', settlement_way: '' },
      {
      
       settlement_type: '3', limit_days: '180', rate: '', settlement_way: '' },
      {
      
       settlement_type: '3', limit_days: '90', rate: '', settlement_way: '' },
    ]
  }]
})

const formRules = {
      
      
  rate: [{
      
       required: true, validator: validatePercentageNumber, trigger: 'blur' }],
  settlement_way: [{
      
       required: true, trigger: 'change', message: '请选择' }],
  first_rate: [{
      
       required: true, validator: validatePercentageNumber, trigger: 'blur' }]
}

const giveModelList = [
  {
      
       key: '1', val: '一次性发放' },
  {
      
       key: '2', val: '每天发放' },
  {
      
       key: '3', val: '首次+每天' }
]
</script>

<style lang="less" scoped></style>

plan 1:

This method is the simplest, by directly judging settlement_waywhether the word of the sub-array is equal to '3'

   v-if="itemChild.settlement_way === '3'"

Scenario 2:

At first, I didn't expect to use settlement_waywhether the field is equal to '3', which can be solved directly. Another method is used, and it is also recorded that this method is often used.

  1. Create a new array, and if it meets the judgment conditions, use 父级index和子级indexto assemble it 字符串, and then push it into the new array;
  2. If the judgment condition is not met, for loop the new array, if there is a certain value in the currently 父级index和子级indexassembled string array, delete the value from the array.等于
  3. In html, v-ifit is judged whether ( includes) contains the value in the array, and if so, it will directly display the first rate input, otherwise it will be hidden.
<a-col :span="8">
   <a-form-item
     :field="`templateList[${index}].list[${indexChild}].settlement_way`"
      label="发放方式"
      :rules="formRules.settlement_way"
    >
      <a-select
         v-model="itemChild.settlement_way"
         placeholder="请选择"
         allow-clear
         @change="((val) => {
         changeSelect(val,index,indexChild,itemChild)
         })"
       >
         <a-option
           v-for="item in giveModelList"
           :key="item.key"
           :label="item.val"
           :value="item.key"
          />
      </a-select>
   </a-form-item>
</a-col>
 <a-col
    :span="8"
     v-if="indexArr.length > 0 && indexArr.includes(`${index}${indexChild}`)"
 >
     <a-form-item
       :field="`templateList[${index}].list[${indexChild}].first_rate`"
       label="首发比例"
       :rules="formRules.first_rate"
      >
         <a-input
           v-model="itemChild.first_rate"
           placeholder="请填写"
           allow-clear
          >
           <template #append>
             %
           </template>
         </a-input>
 </a-form-item>
</a-col>
const indexArr = ref([])
function changeSelect(val:any, index:any, indexChild:any, itemChild:any) {
    
    
  if (val == '3') {
    
    
    indexArr.value.push(`${
      
      index}${
      
      indexChild}`)
  } else {
    
    
    for (let i = 0; i < indexArr.value.length; i++) {
    
    
      if (`${
      
      index}${
      
      indexChild}` == indexArr.value[i]) {
    
    
        indexArr.value.splice(i, 1)
      }
    }
    delete itemChild.first_rate
  }
  console.log(indexArr.value, 'indexArr') // ['00','10','21','22','23']
}

Print result:

insert image description here

4. Form validation for arrays of complex objects

Because all items are required, it involves the verification of each item in the sub-array. Validation needs to be added to each element.
Take a look at the effect diagram of this verification first.

insert image description here

Known data structures:

const form = reactive({
    
    
  title: '',
  templateList: [{
    
    
    key: 'region',
    label: '名称111',
    list: [{
    
     settlement_type: '1', limit_days: '0', rate: '', settlement_way: '' }]
  }, {
    
    
    key: 'partner',
    label: '名称222',
    list: [{
    
     settlement_type: '2', limit_days: '0', rate: '', settlement_way: '' }]
  }, {
    
    
    key: 'user',
    label: '名称333',
    list: [
      {
    
     settlement_type: '3', limit_days: '30', rate: '', settlement_way: '' },
      {
    
     settlement_type: '3', limit_days: '60', rate: '', settlement_way: '' },
      {
    
     settlement_type: '3', limit_days: '180', rate: '', settlement_way: '' },
      {
    
     settlement_type: '3', limit_days: '90', rate: '', settlement_way: '' },
    ]
  }]
})

const formRules = {
    
    
  rate: [{
    
     required: true, validator: validatePercentageNumber, trigger: 'blur' }],
  settlement_way: [{
    
     required: true, trigger: 'change', message: '请选择' }],
  first_rate: [{
    
     required: true, validator: validatePercentageNumber, trigger: 'blur' }]
}

After defining the verification rules, you only need to set :fieldthe path in the data object. :field=" templateList[${index}].list[${indexChild}].rate"

  <div
        class="outline"
        v-for="(item,index) in form.templateList"
        :key="index"
      >
        <div style="margin-bottom:10px;">
          {
   
   { item.label }}
        </div>
        <a-row
          :gutter="15"
          v-for="(itemChild,indexChild) in item.list"
          :key="indexChild"
        >
          <a-col :span="8">
            <a-form-item
              :field="`templateList[${index}].list[${indexChild}].rate`"
              :label="Number(itemChild.limit_days) > 0 ? itemChild.limit_days + '天利息':'利息'"
              :rules="formRules.rate"
            >
              <a-input
                v-model="itemChild.rate"
                placeholder="请填写"
                allow-clear
              >
                <template #append>
                  %
                </template>
              </a-input>
            </a-form-item>
          </a-col>

Guess you like

Origin blog.csdn.net/weixin_45811256/article/details/131670833