美文网首页
vue3 + ant-design-vue自定义组合表单项for

vue3 + ant-design-vue自定义组合表单项for

作者: 很好就这样吧 | 来源:发表于2023-11-27 11:37 被阅读0次

    效果图:

    重点:
    1、父级rc-form-item 上不要加 prop,要分别加在内部的各个表单元素上

    2、自定组件内部表单元素上的prop写法要用这种拼接的方式
    :prop="props.attValName + '.selectVal'"
    :prop="props.attValName + '.' + index + '.value'"
    而不是下面这种,下面的写法无法触发校验
    :prop="props.attValName[ index ].value'"

    3、要达到父级form能控制自定义组件内部的各个表单元素的校验和数据回显、重置等能力,
    自定义组件的state定义的数据格式尤为重要,以地址级联组件AttrAddress为例:
    emit('update:modelValue', state.attVals)
    即props.modelValue 所包含的数据,要被state.attVals全部包含,这样就可以由父级的form完全托管校验重置等能力。

    源码:
    index.vue

    <template>
      <!-- 自定义组件 使用样例 -->
      <div>
        <rc-form ref="formRef" :model="form" :rules="rules" label-width="146px">
          <rc-form-item label-width="0">
            <!-- 注意这里的 rc-form-item 不要加prop 做规则校验,通过required控制是否必填,内部校验-->
            <AttrSelectAlias
              v-model="form.attrSelectAlias"
              :att-id="238290"
              att-name="属性值可别名"
              att-val-name="attrSelectAlias"
              :required="true"
              extra=""
            />
          </rc-form-item>
          <rc-form-item label-width="0">
            <!-- 注意这里的 rc-form-item 不要加prop 做规则校验,通过required控制是否必填,内部校验-->
            <AttrSelectPercent
              v-model="form.attrSelectPercent"
              :att-id="217746"
              att-name="复选百分比"
              att-val-name="attrSelectPercent"
              :required="true"
              extra=""
              label-width="146px"
            />
          </rc-form-item>
    
          <rc-form-item label-width="0">
            <!-- 注意这里的 rc-form-item 不要加prop 做规则校验,通过required控制是否必填,内部校验-->
            <AttrCombinedInputs
              v-model="form.combinedInputs2"
              extra=""
              :att-id="238296"
              att-name="组合输入框有前缀"
              att-val-name="combinedInputs2"
              :required="true"
              :prefix-list="prefixList2"
              :unit-list="unitList1"
            />
          </rc-form-item>
    
          <rc-form-item label-width="0">
            <!-- 注意这里的 rc-form-item 不要加prop 做规则校验,通过required控制是否必填,内部校验-->
            <AttrCascader
              v-model="form.cascader"
              :att-id="238291"
              att-name="级联选择"
              att-val-name="cascader"
              :required="true"
              label-width="146px"
            />
          </rc-form-item>
    
          <rc-form-item label-width="0">
            <!-- 注意这里的 rc-form-item 不要加prop 做规则校验,通过required控制是否必填,内部校验-->
            <AttrAddress
              v-model="form.attrAddress2"
              :att-id="238841"
              att-name="地址级联选择4级"
              att-val-name="attrAddress2"
              :level="4"
              :required="true"
              label-width="146px"
            />
          </rc-form-item>
    
          <rc-form-item>
            <rc-button type="primary" size="large" @click="submitForm(formRef)"> 提交 </rc-button>
            <rc-button plain size="large" @click="resetForm(formRef)"> 重置 </rc-button>
          </rc-form-item>
        </rc-form>
      </div>
    </template>
    
    <script lang="ts" setup>
    import { reactive, ref } from 'vue'
    import type { FormInstance, FormRules } from 'ant-design-vue'
    
    import AttrSelectAlias from './components/AttrSelectAlias/index.vue'
    import AttrSelectPercent from './components/AttrSelectPercent/index.vue'
    import AttrCombinedInputs, {
      prefixList1,
      prefixList2,
      unitList1,
    } from './components/AttrCombinedInputs/index.vue'
    import AttrCascader from './components/AttrCascader/index.vue'
    import AttrAddress from './components/AttrAddress/index.vue'
    
    const formRef = ref<FormInstance>()
    const form = reactive({
      attrSelectAlias: { selectVal: '1093079', alias: '我是别名' },
      // attrSelectAlias: undefined,
      attrSelectPercent: [], // 复选百分比
      // combinedInputs2:undefined,
      combinedInputs2: [
        { prefix: '长', value: '100', valueUnit: 'cm' },
        { prefix: '宽', value: '50', valueUnit: 'ml' },
        { prefix: '高', value: '10', valueUnit: 'cm' },
      ],
      // cascader: undefined, // 级联选择
      cascader: [1093079, 1093081], // 级联选择
      attrAddress2: { address: ['1', '2901', '55549'], isOverSea: false },
    })
    const rules = reactive<FormRules>({})
    
    const submitForm = async (formEl: FormInstance | undefined) => {
      if (!formEl) return
      await formEl.validate((valid, fields) => {
        if (valid) {
          console.log('submit!===', form)
        } else {
          console.log('error submit!-fields', fields)
        }
      })
    }
    
    const resetForm = (formEl: FormInstance | undefined) => {
      if (!formEl) return
      formEl.resetFields()
    }
    </script>
    <style lang="scss" scoped></style>
    

    ./components/AttrSelectAlias/index.vue

    <template>
      <!-- 属性值 可别名:下拉选择框 + 输入框 -->
      <rc-form-item
        :label="props.attName"
        :prop="props.attValName + '.selectVal'"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
      >
        <rc-select
          v-model="state.attVal.selectVal"
          placeholder="请选择"
          :multiple="props.multiple"
          clearable
          style="width: 320px"
          @change="onSelectChange"
        >
          <rc-option
            v-for="item in state.options"
            :key="item.id"
            :label="item.name"
            :value="item.id.toString()"
          />
        </rc-select>
      </rc-form-item>
    
      <rc-form-item
        style="margin-left: 8px"
        :prop="props.attValName + '.alias'"
        :rules="{
          required: props.required,
          message: '请输入别名',
          trigger: 'blur',
        }"
      >
        <rc-input
          v-model="state.attVal.alias"
          placeholder="请输入别名"
          style="width: 320px"
          @input="onInputChange"
        />
      </rc-form-item>
    
      <div v-if="extra" class="extra"> 备注&示例:{{ extra }} </div>
    </template>
    
    <script lang="ts">
    interface AttValue {
      selectVal: string
      alias: string
    }
    interface AttValueItem {
      id: number
      name: string
    }
    </script>
    <script setup lang="ts">
    import { onMounted, reactive } from 'vue'
    import mockData from '../../mock.json'
    
    const props = defineProps({
      modelValue: {
        type: Object,
        default: undefined,
      },
      attId: {
        type: Number,
        default: undefined,
      },
      attName: {
        type: String,
        default: undefined,
      },
      attValName: {
        type: String,
        default: undefined,
      },
      required: {
        type: Boolean,
        default: false,
      },
      multiple: {
        type: Boolean,
        default: false,
      },
      disabled: {
        type: Boolean,
        default: false,
      },
      extra: {
        type: String,
        default: '',
      },
      labelWidth: {
        type: String,
        default: '',
      },
    })
    const emit = defineEmits(['update:modelValue', 'change', 'blur'])
    
    const state = reactive<{
      attVal: AttValue
      options: AttValueItem[]
    }>({
      attVal: { selectVal: '', alias: '' },
      options: [],
    })
    onMounted(() => {
      getData()
    })
    
    const getData = () => {
      if (!props.attId) return
      // 接口获取选择框下拉选项
      setTimeout(() => {
        state.options = mockData
        initAttVal()
      }, 300)
    }
    
    const initAttVal = () => {
      // console.log('props.modelValue===', props.modelValue)
      if (!props.modelValue || props.modelValue?.length == 0) {
        // 初始没有值
        state.attVal = { selectVal: '', alias: '' }
      } else {
        // 回显
        state.attVal = props.modelValue as AttValue
      }
    
      emit('update:modelValue', state.attVal)
      emit('change')
    }
    
    const onInputChange = () => {
      // console.log('onInputChange===', state.alias)
    }
    const onSelectChange = () => {
      // console.log('onSelectChange===', state.selectVal)
    }
    </script>
    <style lang="scss" scoped>
    .extra {
      margin-left: 8px;
      color: var(--rcd-color-text-200);
      font-size: 12px;
    }
    </style>
    

    ./components/AttrSelectPercent/index.vue

    <template>
      <!-- 复选百分比:选择框+输入框+%  -->
      <rc-form-item
        v-for="(attVal, index) in state.attVals"
        :key="index"
        :style="{ marginBottom: index == state.attVals.length - 1 ? '0' : '20px' }"
      >
        <rc-form-item
          :label="index == 0 ? props.attName : ''"
          :prop="props.attValName + '.' + index + '.value'"
          :rules="{
            required: props.required,
            message: '请选择',
            trigger: 'change',
          }"
          :label-width="props.labelWidth"
        >
          <rc-select
            v-model="state.attVals[index].value"
            placeholder="请选择"
            :style="{
              width: '220px',
            }"
            @change="onSelectChange"
          >
            <rc-option
              v-for="item in state.options"
              :key="item.id"
              :label="item.name"
              :value="item.id.toString()"
            />
          </rc-select>
        </rc-form-item>
    
        <rc-form-item
          :prop="props.attValName + '.' + index + '.percentage'"
          :rules="{
            required: props.required,
            message: '请输入',
            trigger: 'blur',
          }"
        >
          <rc-input
            v-model="state.attVals[index].percentage"
            placeholder="请输入"
            class="input"
            :maxlength="3"
            @change="onInputChange"
          >
            <template #append> % </template>
          </rc-input>
    
          <rc-button style="margin-left: 8px" @click.prevent="removeDomain(attVal)"> 删除 </rc-button>
        </rc-form-item>
      </rc-form-item>
      <rc-button style="margin-left: 8px" @click="addDomain"> 新增 </rc-button>
    
      <div v-if="extra" class="extra"> 备注&示例:{{ extra }} </div>
    </template>
    
    <script lang="ts">
    interface AttValItem {
      value: string
      percentage: string
      valUnit: string
    }
    interface AttValueItem {
      id: number
      name: string
    }
    </script>
    
    <script setup lang="ts">
    import { reactive, onMounted } from 'vue'
    import mockData from '../../mock.json'
    
    const props = defineProps({
      modelValue: {
        type: Array,
        default: undefined,
      },
      attId: {
        type: Number,
        default: undefined,
      },
      attName: {
        type: String,
        default: undefined,
      },
      attValName: {
        type: String,
        default: undefined,
      },
      required: {
        type: Boolean,
        default: false,
      },
      disabled: {
        type: Boolean,
        default: false,
      },
      extra: {
        type: String,
        default: '',
      },
      labelWidth: {
        type: String,
        default: '',
      }
    })
    const emit = defineEmits(['update:modelValue', 'change'])
    
    const state = reactive<{
      attVals: AttValItem[]
      options: AttValueItem[]
    }>({
      attVals: [],
      options: [],
    })
    
    onMounted(() => {
      getData()
    })
    
    const removeDomain = (item: AttValItem) => {
      const index = state.attVals.indexOf(item)
      if (index !== -1) {
        state.attVals.splice(index, 1)
      }
    }
    
    const addDomain = () => {
      state.attVals.push({ value: '', percentage: '', valUnit: '%' })
    }
    
    const getData = () => {
      if (!props.attId) return
      // 接口获取选择框下拉选项
      setTimeout(()=>{
        state.options = mockData
        initAttVal()
    
        emit('update:modelValue', state.attVals)
        emit('change')
      },300)
    }
    
    const initAttVal = () => {
      // console.log('props.modelValue===', props.modelValue)
      if (!props.modelValue || props.modelValue?.length == 0) {
        // 初始没有值
        addDomain()
      } else {
        // 回显
        state.attVals = props.modelValue as AttValItem[]
      }
    }
    
    const onInputChange = () => {
      // console.log('onInputChange===', state.attVal)
    }
    const onSelectChange = () => {
      // console.log('onSelectChange===', state.attVal)
    }
    </script>
    <style lang="scss" scoped>
    .extra {
      margin-left: 8px;
      color: var(--rcd-color-text-200);
      font-size: 12px;
    }
    .input {
      width: 104px;
      margin-left: -4px;
      :deep(.rcd-input__wrapper) {
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
      }
    }
    </style>
    

    ./components/AttrCombinedInputs/index.vue

    <template>
      <!-- 组合类型:前缀(+/-/''/长/宽/高) + 输入框 + 单位下拉选择框  -->
      <rc-form-item v-for="(prefix, index) in state.prefixList" :key="index">
        <rc-form-item
          :label="index == 0 ? props.attName : ''"
          :prop="props.attValName + '.' + index + '.value'"
          :rules="{
            required: props.required,
            message: '请输入',
            trigger: 'blur',
          }"
        >
          <rc-input
            v-model="state.attVal[index].value"
            placeholder="请输入"
            :style="{ width: state.prefixList.length == 1 ? '320px' : '200px' }"
            @change="onInputChange"
          >
            <template v-if="prefix" #prepend>
              <div style="width: 14px">
                {{ prefix }}
              </div>
            </template>
            <template #append>
              <rc-select style="width: 71px" />
            </template>
          </rc-input>
        </rc-form-item>
        <rc-form-item :prop="props.attValName + '.' + index + '.valueUnit'">
          <rc-select
            v-model="state.attVal[index].valueUnit"
            class="select"
            :style="{ marginRight: index == state.prefixList.length - 1 ? 0 : '24px' }"
            @change="onUnitChange"
          >
            <rc-option v-for="(unit, idx) in state.unitList" :key="idx" :label="unit" :value="unit" />
          </rc-select>
        </rc-form-item>
      </rc-form-item>
    
      <div v-if="extra" class="extra"> 备注&示例:{{ extra }} </div>
    </template>
    
    <script lang="ts">
    interface AttValItem {
      prefix: string
      value: string
      valueUnit: string
    }
    // 自测数据
    export const prefixList2 = ['长', '宽', '高'] // 有前缀
    export const prefixList1 = [''] // 没有前缀
    export const unitList1 = ['mm', 'cm', 'm']
    </script>
    
    <script setup lang="ts">
    import { reactive, onMounted } from 'vue'
    
    const props = defineProps({
      modelValue: {
        type: Array,
        default: undefined,
      },
      attId: {
        type: Number,
        default: undefined,
      },
      attName: {
        type: String,
        default: undefined,
      },
      attValName: {
        type: String,
        default: undefined,
      },
      required: {
        type: Boolean,
        default: false,
      },
      disabled: {
        type: Boolean,
        default: false,
      },
      prefixList: {
        type: Array,
        default() {
          return []
        },
      },
      unitList: {
        type: Array,
        default() {
          return []
        },
      },
      extra: {
        type: String,
        default: '',
      },
    })
    const emit = defineEmits(['update:modelValue', 'change'])
    
    const state = reactive({
      attVal: [] as AttValItem[],
      prefixList: [] as string[],
      unitList: [] as string[],
    })
    
    onMounted(() => {
      getData()
    })
    
    const getData = () => {
      setTimeout(() => {
        state.prefixList = props.prefixList as string[]
        state.unitList = props.unitList as string[]
    
        initAttVal()
    
        emit('update:modelValue', state.attVal)
        emit('change')
      }, 1000)
    }
    
    const initAttVal = () => {
      // console.log('props.modelValue===', props.modelValue)
      if (!props.modelValue || props.modelValue?.length == 0) {
        // 初始没有值
        state.attVal = state.prefixList.map((prefix) => {
          return { prefix, value: '', valueUnit: state.unitList[0] }
        })
      } else {
        // 回显
        state.attVal = state.prefixList.map((prefix) => {
          const temp = props.modelValue?.find((item: any) => item.prefix == prefix) as AttValItem
          return { prefix, value: temp?.value, valueUnit: temp?.valueUnit }
        })
      }
    }
    
    const onInputChange = () => {
      // console.log('onInputChange===', state.attVal)
    }
    const onUnitChange = () => {
      // console.log('onUnitChange===', state.attVal)
    }
    </script>
    <style lang="scss" scoped>
    .extra {
      margin-left: 8px;
      color: var(--rcd-color-text-200);
      font-size: 12px;
    }
    
    .select {
      width: 72px;
      margin-left: -72px;
      z-index: 2;
    
      :deep(.rcd-input__wrapper) {
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
      }
    }
    </style>
    

    ./components/AttrCascader/index.vue

    <template>
      <!-- 针对动态获取数据,且级联层级不确定的情况,有的选项层级多,有的选项层级少 -->
      <rc-form-item
        :label="props.attName"
        :prop="props.attValName + '.' + 0"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
        :label-width="props.labelWidth"
      >
        <rc-select
          v-model="state.attVals[0]"
          placeholder="请选择"
          :disabled="props.disabled"
          style="width: 320px; margin-right: 8px"
          @change="onChange1"
        >
          <rc-option
            v-for="item in option.options1"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          />
        </rc-select>
      </rc-form-item>
      <rc-form-item
        v-if="option.options2.length > 0"
        :prop="props.attValName + '.' + 1"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
      >
        <rc-select
          v-model="state.attVals[1]"
          placeholder="请选择"
          :disabled="props.disabled"
          style="width: 320px"
          @change="onChange2"
        >
          <rc-option
            v-for="item in option.options2"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          />
        </rc-select>
      </rc-form-item>
    
      <div v-if="extra" class="extra"> 备注&示例:{{ extra }} </div>
    </template>
    
    <script lang="ts">
    interface AttValueByLevelItem {
      id: number
      name: string
    }
    </script>
    <script setup lang="ts">
    import { onMounted, reactive } from 'vue'
    import mockData from '../../mock.json'
    
    const props = defineProps({
      modelValue: {
        type: Array,
        default: undefined,
      },
      attId: {
        type: Number,
        default: undefined,
      },
      attName: {
        type: String,
        default: undefined,
      },
      attValName: {
        type: String,
        default: undefined,
      },
      required: {
        type: Boolean,
        default: false,
      },
      disabled: {
        type: Boolean,
        default: false,
      },
      extra: {
        type: String,
        default: '',
      },
      labelWidth: {
        type: String,
        default: '',
      },
    })
    const emit = defineEmits(['update:modelValue', 'change'])
    
    const state = reactive({
      attVals: [] as number[],
    })
    
    const option = reactive<{ [key: string]: AttValueByLevelItem[] }>({
      options1: [],
      options2: [],
    })
    
    const getData = (level: number, parentId?: number, cb?: (hasNext: boolean) => void) => {
      // const params = {
      //   attId: props.attId,
      //   attLevel: level,
      //   parentId,
      // }
      // getAttValueByLevel(params).then((res) => {
      //   option['options' + level] = res || []
      //   cb && cb(res ? true : false)
      // })
      setTimeout(()=>{
        const res = mockData
        option['options' + level] = res || []
        cb && cb(res ? true : false)
      },300)
    }
    
    const onChange1 = (val: number) => {
      state.attVals.splice(1, 1) // 删掉第二个
      option.options2 = []
      getData(2, val)
    }
    const onChange2 = (val: number) => {
      //
    }
    
    const initAttVal = () => {
      // console.log('props.modelValue===', props.modelValue)
      if (!props.modelValue || props.modelValue?.length == 0) {
        // 初始没有值
      } else {
        // 回显
        state.attVals = props.modelValue as number[]
        if (props.modelValue.length > 1) {
          getData(2, state.attVals[0])
        }
      }
    }
    
    onMounted(() => {
      getData(1, undefined, () => {
        initAttVal()
        emit('update:modelValue', state.attVals)
        emit('change')
      })
    })
    </script>
    <style lang="scss" scoped>
    .extra {
      margin-left: 8px;
      color: var(--rcd-color-text-200);
      font-size: 12px;
    }
    </style>
    

    ./components/AttrAddress/index.vue

    <template>
      <!-- 地址级联选择,动态获取下一级,且层级数不定,可能3级可能4级 -->
      <rc-form-item
        style="width: 100%"
        :label="props.attName"
        :label-width="props.labelWidth"
        :prop="props.attValName + '.isOverSea'"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
      >
        <rc-radio-group v-model="state.attVals.isOverSea" @change="onIsOverSeaChange">
          <rc-radio :label="false"> 国内 </rc-radio>
          <rc-radio :label="true"> 海外 </rc-radio>
        </rc-radio-group>
      </rc-form-item>
    
      <rc-form-item
        :label-width="props.labelWidth"
        :prop="props.attValName + '.address.' + 0"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
      >
        <rc-select
          v-model="state.attVals.address[0]"
          placeholder="请选择"
          style="width: 200px; margin-right: 8px"
          @change="(v: any) => onChange(v, 0 + 1)"
        >
          <rc-option
            v-for="item in option['options' + (0 + 1)]"
            :key="item.districtId"
            :label="item.districtName"
            :value="item.districtId.toString()"
          />
        </rc-select>
      </rc-form-item>
    
      <rc-form-item
        v-if="option.options2.length > 0"
        :prop="props.attValName + '.address.' + 1"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
      >
        <rc-select
          v-model="state.attVals.address[1]"
          placeholder="请选择"
          style="width: 200px; margin-right: 8px"
          @change="(v: any) => onChange(v, 1 + 1)"
        >
          <rc-option
            v-for="item in option['options' + (1 + 1)]"
            :key="item.districtId"
            :label="item.districtName"
            :value="item.districtId.toString()"
          />
        </rc-select>
      </rc-form-item>
    
      <rc-form-item
        v-if="option.options3.length > 0"
        :prop="props.attValName + '.address.' + 2"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
      >
        <rc-select
          v-model="state.attVals.address[2]"
          placeholder="请选择"
          style="width: 200px; margin-right: 8px"
          @change="(v: any) => onChange(v, 2 + 1)"
        >
          <rc-option
            v-for="item in option['options' + (2 + 1)]"
            :key="item.districtId"
            :label="item.districtName"
            :value="item.districtId.toString()"
          />
        </rc-select>
      </rc-form-item>
    
      <rc-form-item
        v-if="option.options4.length > 0"
        :prop="props.attValName + '.address.' + 3"
        :rules="{
          required: props.required,
          message: '请选择',
          trigger: 'change',
        }"
      >
        <rc-select
          v-model="state.attVals.address[3]"
          placeholder="请选择"
          style="width: 200px"
          @change="(v: any) => onChange(v, 3 + 1)"
        >
          <rc-option
            v-for="item in option['options' + (3 + 1)]"
            :key="item.districtId"
            :label="item.districtName"
            :value="item.districtId.toString()"
          />
        </rc-select>
      </rc-form-item>
    
      <div v-if="extra" class="extra"> 备注&示例:{{ extra }} </div>
    </template>
    
    <script setup lang="ts">
    import { onMounted, reactive } from 'vue'
    import { getAddressByParentId } from '@/services/productIntroduction'
    
    const props = defineProps({
      modelValue: {
        type: Object,
        default: undefined,
      },
      attId: {
        type: Number,
        default: undefined,
      },
      // 可选层级
      level: {
        type: Number,
        default: 1,
      },
      attName: {
        type: String,
        default: undefined,
      },
      attValName: {
        type: String,
        default: undefined,
      },
      required: {
        type: Boolean,
        default: false,
      },
      multiple: {
        type: Boolean,
        default: false,
      },
      disabled: {
        type: Boolean,
        default: false,
      },
      extra: {
        type: String,
        default: '',
      },
      labelWidth: {
        type: String,
        default: '',
      },
    })
    const emit = defineEmits(['update:modelValue', 'change'])
    
    interface AttValue {
      address: string[]
      isOverSea: boolean
    }
    
    const state = reactive<{ attVals: AttValue }>({
      attVals: {
        address: [],
        isOverSea: false,
      },
    })
    
    interface AddressItem {
      districtId: number
      districtName: string
      districtFatherId: number
    }
    const option = reactive<{ [key: string]: AddressItem[] }>({
      options1: [],
      options2: [],
      options3: [],
      options4: [],
    })
    
    const getData = (parentId: string, level: number, cb?: (hasNext: boolean) => void) => {
      getAddressByParentId({ parentId }).then((res) => {
        option['options' + level] = res.output?.areas || []
        cb && cb(res.output?.areas ? true : false)
      })
    }
    
    const onChange = (val: string, level: number) => {
      switch (level) {
        case 1:
          onChange1(val)
          break
        case 2:
          onChange2(val)
          break
        case 3:
          onChange3(val)
          break
        case 4:
          onChange4(val)
          break
      }
    }
    
    const onChange1 = (val: string) => {
      if (props.level <= 1) {
        //
      } else {
        // 截取数组,指定长度
        const len = state.attVals.address.length
        state.attVals.address.splice(1, len - 1)
    
        option.options2 = []
        option.options3 = []
        option.options4 = []
    
        getData(val, 2)
      }
    }
    const onChange2 = (val: string) => {
      if (props.level <= 2) {
        //
      } else {
        const len = state.attVals.address.length
        state.attVals.address.splice(2, len - 2)
    
        option.options3 = []
        option.options4 = []
    
        getData(val, 3)
      }
    }
    const onChange3 = (val: string) => {
      if (props.level <= 3) {
        //
      } else {
        const len = state.attVals.address.length
        state.attVals.address.splice(3, len - 3)
    
        option.options4 = []
    
        getData(val, 4)
      }
    }
    const onChange4 = (val: string) => {
      //
    }
    
    const onIsOverSeaChange = (isOverSea: number) => {
      // 重置地址选择框
      const len = state.attVals.address.length
      state.attVals.address.splice(0, len)
      option.options1 = []
      option.options2 = []
      option.options3 = []
      option.options4 = []
      const parentId = isOverSea ? '53283' : '4744'
      getData(parentId, 1) // 获取第一级选项
    }
    
    const initAttVal = () => {
      // console.log('props.modelValue===', props.modelValue)
      if (!props.modelValue) {
        // 初始没有值
      } else {
        // 回显
        state.attVals = props.modelValue as AttValue
        if (state.attVals.address.length > 1) {
          getData(state.attVals.address[0], 2)
        }
        if (state.attVals.address.length > 2) {
          getData(state.attVals.address[1], 3)
        }
        if (state.attVals.address.length > 3) {
          getData(state.attVals.address[2], 4)
        }
      }
    }
    
    onMounted(() => {
      const parentId = props.modelValue?.isOverSea ? '53283' : '4744'
    
      getData(parentId, 1, () => {
        initAttVal()
        emit('update:modelValue', state.attVals)
        emit('change')
      })
    })
    </script>
    <style lang="scss" scoped>
    .extra {
      margin-left: 8px;
      color: var(--rcd-color-text-200);
      font-size: 12px;
    }
    </style>
    

    mock.json

    [
        {
            "id": 1093079,
            "name": "测试1"
        },
        {
            "id": 1093080,
            "name": "测试2"
        },
        {
            "id": 1093081,
            "name": "测试3"
        }
    ]
    

    相关文章

      网友评论

          本文标题:vue3 + ant-design-vue自定义组合表单项for

          本文链接:https://www.haomeiwen.com/subject/amgawdtx.html