vuejs - - - - - 递归组件的实现

递归组件的实现

  • 1. 需求描述:
  • 2. 效果图:
  • 3. 代码
    • 3.1 封装组件代码
    • 3.2 父组件使用

1. 需求描述:

  1. 点击添加行,增加一级目录结构
  2. 当类型为object or array时,点击右侧➕,增加子集
  3. 点击右侧,删除对应子集

2. 效果图:

vuejs - - - - - 递归组件的实现_第1张图片

3. 代码

3.1 封装组件代码

<template>
  <template v-if="!!currentLevelData.length">
    <div class="mt10" v-for="(item, index) in currentLevelData" :key="`${deep}-${index}`">
      <div class="flex flex-align-center">
        
        <div class="common mr10 border-box" :style="{ paddingLeft: (deep - 1) * 10 + 'px' }">
          <a-input v-model:value="item.key" placeholder="请输入key" />
        div>

        
        <div class="type mr10">
          <a-select
            ref="select"
            v-model:value="item.type"
            class="full-width"
            @change="handleChange($event, item)"
          >
            <a-select-option v-for="t in dataType" :value="t" :key="t">{{ t }}a-select-option>
          a-select>
        div>

        
        <div class="common mr10">
          <a-textarea
            :rows="1"
            placeholder="请输入参考值"
            v-model:value="item.value"
            :disabled="objectFile.includes(item.type)"
          />
        div>

        
        <div class="common mr10">
          <a-textarea :rows="1" placeholder="请输入备注" v-model:value="item.desc" />
        div>

        
        <div class="flex">
          <delete-outlined class="ml5" @click="deleteTarget(index)" />
          
          <plus-outlined
            class="ml5"
            v-show="objectFile.includes(item.type)"
            @click="addSubset(item)"
          />
        div>
      div>

      <template v-if="!!item.child?.length">
        
        <CustomInputGroup :deep="deep + 1" :list="item.child" />
      template>
    div>
  template>
template>
<script lang="ts" setup>
import CustomInputGroup from './index.vue';
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';

const dataType = ['string', 'number', 'boolean', 'object', 'array', 'file']; // 所有的类型

const props = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
  deep: {
    type: Number,
    default: 1,
  },
});

const objectFile = ['object', 'array']; // 可以有下一级结构的类型

interface paramsItem {
  key: string;
  type: string;
  value: string;
  desc: string;
  child?: any;
}

// currentLevelData:永远是当前层次的数据 - 数据源来自于组件调用时传递的
// 监听props变化
const currentLevelData: any = computed(() => {
  return props.list;
});

/**
 * 切换类型
 */
function handleChange(type: string, item: any) {
  if (objectFile.includes(type)) {
    item.value = '';
    item.child = [];
  } else {
    delete item.child;
  }
}

/**
 * 添(追)加子集
 */
function addSubset(item: any) {
  const lastDeep = props.deep;
  if (lastDeep == 5) return message.info('最多支持5层结构', 2);
  item.value = '';
  item.value = '';
  item.child.push({
    key: `params${props.deep + 1}-${item.child.length + 1}`,
    type: 'string',
    value: '',
    desc: '',
  });
}

/**
 * 删除
 */
function deleteTarget(index: number) {
  currentLevelData.value.splice(index, 1);
}

/**
 * 获取数据
 */
function getChildParams() {
  return currentLevelData.value;
}
/**
 * 将子组件方法暴露给父组件
 */
defineExpose({
  addSubset,
  getChildParams,
});
script>
<style lang="less" scoped>
.common {
  width: 135px;
}
.type {
  width: 100px !important;
}
style>

3.2 父组件使用

<template>
	 <CustomInputGroup ref="paramRef" :list="formState.param" :deep="1" />
     <a-button class="mt10" type="primary" @click="addLineParam('param')"> 添加行 a-button>
template>



<script>
const formState = ({
	param:[]
})

/**
 * 添加行(headersParam、requestParam)
 */
function addLineParam(formStateKey: string) {
  formState[formStateKey].push({
    key: `params${formState[formStateKey].length + 1}`,
    type: 'string',
    value: '',
    desc: '',
  });
}
script>

你可能感兴趣的:(vue,javascript,vue.js)