vue中递归组件的使用

组件中需要组件调用自身,这就是递归组件,递归组件需要声明name和自己引入自己并声明注册为组件,并且需要使用props进行传参,其还需要一个停止条件,否则会进入死循环。

vue的递归组件和其v-for指令之间的关系和js中的for循环和递归函数一样,一个是有尽头,一个是不知道到底嵌套了多少层级。在vue中我们是数据驱动界面,根据数据来渲染界面,而很多数据我们是从后台获取,事先并不知道它会嵌套多少层,这时候使用v-for指令就不能满足我们的要求了,需要使用递归组件,这就和js中的递归函数一个道理!

效果图:

如图所示,当用户操作界面添加条件时,我们就需要在相应层级的添加一行,然而我们不知道用户具体会添加多少层条件,这时候使用v-for指令来遍历数据进行循环就不怎么合适了,这时候就时递归组件大展身手的时候!

父组件代码:

 <div class="filter-context">
      <div class='contain ' :class='{borderShow:item.list.length>0}' v-for="(item,index) in filterData" :key='index'>
        <s-table ref='tabled' @change='change' :item='item' :filterData='filterData'></s-table>
      </div>
    </div>

子组件代码:

<template>
  <div class='children' v-if='item.list'>
    <div class="context-left" v-if='item.list.length>1'>
      <span>{{item.con}}</span>
    </div>
    <div class="context-right">
      <div class="context" v-for="(data,i) in item.list" :key="i">
        <div class='context-every' v-if='data.id'>
          <div v-show='!data.ifShowField'>
            <span class='filter-field' :title='data.field' @click='fieldClick(i, item.list,item.con,data)'>{{data.field}}</span>
          </div>
          <div v-show='data.ifShowField'>
            <span class='choose-field' @click.stop='toggle(i)'>请选择字段</span>
            <div class='tree' v-show='nowIndex === i && ifTree'>
              <el-tree :render-content="renderContent" :data="treeData" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
            </div>
          </div>
        </div>
        <div class="context-every" v-if='data.id' v-show='data.recordEvery'>
          <p class='borderStyle'></p>
        </div>
        <s-table :item='data' @change='change' :filterData='filterData'></s-table>
      </div>
    </div>
  </div>
</template>
<script>
import STable from "./STable";
import uuId from "node-uuid";
export default {
  name: "STable",
  props: ["item", "filterData"],
  data() {
    return {
      fieldArr: [],
      con: "",
      treeData: [
        {
          label: "1",
          children: [
            {
              label: "2 ",
              type: "1"
            }
          ]
        },
        {
          label: "3",
          children: [
            {
              label: "4",
              type: "2"
            },
            {
              label: "5",
              type: "3"
            }
          ]
        },
        {
          label: "6",
          children: [
            {
              label: "7",
              type: "1"
            },
            {
              label: "8",
              type: "1"
            }
          ]
        }
      ],
      defaultProps: {
        children: "children",
        label: "label"
      },
      nowIndex: null, //选择字段当前的 下标
      ifTree: false, //选择字段的 树状下拉列表是否展示
      // ifShowField: [], //显示 字段false 还是 选择字段true 的布尔值数组
      ifCondition: false, //添加条件的两种展现形式,判断展示哪个
      ifCon: false, //是否展示 含有且或条件
      recordIndex: null, // 每条过滤条件  文字的下标
      recordField: [] //记录每条过滤条件点击的文字
      // recordEvery: [] //list 列表 遍历 阴影框
    };
  },
  components: {
    STable
  },
  methods: {
    // 添加条件的点击事件
    addFilter(bool) {
      this.ifCondition = bool;
    },
    // 请选择字段的 折叠 展开
    toggle(i) {
      this.ifTree = !this.ifTree;
      this.nowIndex = i;
    },
    // 树形空间  子节点的 点击事件
    handleNodeClick(data, node, itself) {
      if (!data.children) {
        this.item.list[this.nowIndex].field = data.label;
        this.recordField[this.nowIndex] = data.label;
        this.item.list[this.nowIndex].ifShowField = false;
        this.item.list[this.nowIndex].recordEvery = false;
        this.ifTree = false;
      }
    },
    // 每条过滤  条件  字段的点击事件
    fieldClick(index, field, con, data) {
      this.fieldArr = data.id;
      this.recordIndex = index;
      this.ifCondition = false;
      this.isData(this.filterData[0].list, this.fieldArr);
      this.$emit("change", this.ifCondition, con, this.fieldArr);
    },
    //判断阴影框是否显示
    isData(arrData, id) {
      arrData.forEach((item, index) => {
        if (!item.list) {
         
          if (item.id === id) {
            arrData[index].recordEvery = !arrData[index].recordEvery;
            if (arrData[index].recordEvery) {
              this.ifCondition = true;
            } else {
              this.ifCondition = false;
            }
          } else {
            arrData[index].recordEvery = false;
          }
        }else{
          this.isData(item.list, id);
        }
      });
    },
    //添加数据
    addData(arrData, uId, id, con, value) {
      arrData.forEach((item, index) => {
        if (item.id) {
          if (item.id === id) {
            if (con === value) {
              arrData.splice(index + 1, 0, {
                field: "",
                id: uId,
                ifShowField: true,
                recordEvery: false
              });
              arrData[index].recordEvery = false;
            } else {
              var fieldArr = arrData[index];
              var arr = { ...fieldArr, recordEvery: false };
              var obj = {
                con: value,
                list: [
                  { ...arr },
                  { field: "", id: uId, ifShowField: true, recordEvery: false }
                ]
              };
              arrData.splice(index, 1, obj);
            }
          }
        } else {
          this.addData(item.list, uId, id, con, value);
        }
      });
    },
    // 且,或 条件的点击事件
    ifConClick(value, con, id) {
      this.item.list[this.nowIndex].recordEvery = false;
      var uId = uuId();
      if (con) {
        this.addData(this.item.list, uId, id, con, value);
      } else {
        this.filterData[0].con = value;
        this.filterData[0].list.push({
          field: "",
          id: uId,
          ifShowField: true,
          recordEvery: false
        });
      }
      this.$emit("change", false);
    },
    change(ifCondition, con, id) {
      this.$emit("change", ifCondition, con, id);
    },
    // 树形图子节点 放入icon图标
    renderContent(h, { node, data, store }) {
      return (
        <span style="float:left;width: 140px;">
          <i
            class={data.type == "1" ? "el-icon-circle-close" : ""}
            style="float:left;line-height: 20px;"
          />
          <i
            class={data.type == "2" ? "el-icon-date" : ""}
            style="float:left;line-height: 20px;"
          />
          <i
            class={data.type == "3" ? "el-icon-sold-out" : ""}
            style="float:left;line-height: 20px;"
          />
          <span
            title={node.label}
            style="float:left;margin-left: 5px;width: 100px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;"
          >
            {node.label}
          </span>
        </span>
      );
    }
  }
};
</script>

在子组件代码中,我引入了他自身的路径并注册了组件,并且还声明了name,这些是必须的操作!

然后在父组件中我调用了子组件,而在子组件中我又调用了子组件,注意这时在子组件中的调用需要和父组件保持同步,如果在父组件中的调用有进行父子组件的通信,在子组件的调用中也必须有这些!如我在父组件中使用了(@change='change' :item='item' :filterData='filterData')这些代码,我在子组件的调用中也进行了这些操作,这也是递归组件的关键之处,就如js中函数递归的传参一样

数据格式:

   filterData: [
        {
          con: "",
          list: [
            {
              field: "1-1",
              id: "1111",
              ifShowField: true,
              recordEvery: false
            },
            {
              con: "或",
              list: [
                {
                  field: "3-3",
                  id: "3333",
                  ifShowField: true,
                  recordEvery: false
                },
                {
                  con: "或",
                  list: [
                    {
                      field: "3-3",
                      id: "3333",
                      ifShowField: true,
                      recordEvery: false
                    },
                    {
                      field: "aaaaa",
                      id: "7777",
                      ifShowField: true,
                      recordEvery: false
                    }
                  ]
                },
                {
                  field: "aaaaa",
                  id: "7777",
                  ifShowField: true,
                  recordEvery: false
                }
              ]
            },
            {
              con: "或",
              list: [
                {
                  field: "3-3",
                  id: "3333",
                  ifShowField: true,
                  recordEvery: false
                },
                {
                  con: "或",
                  list: [
                    {
                      field: "3-3",
                      id: "3333",
                      ifShowField: true,
                      recordEvery: false
                    },
                    {
                      field: "aaaaa",
                      id: "7777",
                      ifShowField: true,
                      recordEvery: false
                    }
                  ]
                },
                {
                  field: "aaaaa",
                  id: "7777",
                  ifShowField: true,
                  recordEvery: false
                }
              ]
            },
            {
              field: "2-2",
              id: "2222",
              ifShowField: true,
              recordEvery: false
            },
            {
              con: "或",
              list: [
                {
                  field: "3-3",
                  id: "3333",
                  ifShowField: true,
                  recordEvery: false
                },
                {
                  field: "aaaaa",
                  id: "7777",
                  ifShowField: true,
                  recordEvery: false
                }
              ]
            }
       
          ]
        }
      ],

猜你喜欢

转载自blog.csdn.net/qq_39175798/article/details/83056164