前端递归组件的实现

312 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情

曾经遇到一个需要使用递归组件的场景:在页面中动态生成规则,不限制嵌套层级。类似这种结构的还有树形,当可以无限增加子结点时,可以用递归来实现。

递归的核心就是自己调用自己,在代码中组件的递归就是组件自己调用自己,不需要设计得太复杂即可以实现。

设计思路

基础组件的形式如下:

  • 每次新增条件,都是在当前容器内添加一行条件配置
image.png
  • 新增子分组:在当前容器内新增一个子容器(这里就需要进行递归了)
image.png
  • 数据:
    • 递归组件需要共享同一个数据
    • 条件和分组需要区分类型,方便后面递归内容的展示

代码实现

主页面

<RuleBox :object="object"></RuleBox>

子组件

  1. 工具栏部分:
<div>
  <el-select v-model="object.rules">
    <el-option label="且" value="and"/>
    <el-option label="或" value="or"/>
  </el-select>
  <el-button @click="add">新增条件</el-button>
  <el-button @click="addChildern">新增子分组</el-button>
</div>
  1. 条件选项及组件递归:

组件自己调用自己,不需要单独注册组件

<template v-for="(item, index) in object.list">
  <el-row v-if="item.type === 'condition'">
    <el-select v-model="item.select1">
      <el-option label="字段1" value="1"/>
    </el-select>
    <el-select v-model="item.symbol">
      <el-option label="等于" value=""/>
    </el-select>
    <el-select v-model="item.select2">
      <el-option label="字段1" value="1"/>
    </el-select>
    <el-button @click="hadelDelete(index)">删除</el-button>
  </el-row>
  <el-row v-if="item.type === 'group' && item.list.length > 0">
    <rule-box :object="item"></rule-box>
  </el-row>
</template>
  1. 函数实现

添加条件和添加分组的区别就在于,添加分组需要在数据中有一层子条件的嵌套关系:

image.png

注:子容器中 list 字段的长度为 0 的时候,表示容器为空,即为子容器消失的条件,不需要额外为整个容器添加删除按钮

item.type === 'group' && item.list.length > 0
  1. 数据结构

最终的数据结构如下:

image.png

组件传递自定义参数

在递归组件的场景中,可能会在某一层的下拉框或是其他组件操作时对数据进行处理,触发 @change 事件时传递一些自定义参数,而组件也默认携带了部分参数,如果想同时传递,有如下两种方法:

  1. 在模板中使用 this.函数名.bind(this,其它参数)

    @change={ this.onChange.bind(this,'自定义参数') }   
    
  2. 在模板中直接使用箭头函数,将 value 和自定义参数传入

    @change={ value => { this.onChange(value,'自定义参数')} }