vue扁平数据转树形结构递归组件渲染

33 篇文章 1 订阅
12 篇文章 0 订阅

这里使用的是用map映射id和自身然后遍历通过parentid找父级的方法

源扁平数据:

{
    "code": 200,
    "message": "操作成功",
    "data": [
        {
            "functionId": 10000,
            "parentFunctionId": 0,
            "functionName": "安全检测"
        },
        {
            "functionId": 20000,
            "parentFunctionId": 10000,
            "functionName": "工作台"
        },
        {
            "functionId": 20001,
            "parentFunctionId": 10000,
            "functionName": "检测链接"
        },
        {
            "functionId": 20002,
            "parentFunctionId": 10000,
            "functionName": "评论检测"
        },
        {
            "functionId": 20003,
            "parentFunctionId": 10000,
            "functionName": "竞品广告分析"
        },
        {
            "functionId": 10001,
            "parentFunctionId": 0,
            "functionName": "账号设置"
        },
        {
            "functionId": 20004,
            "parentFunctionId": 10001,
            "functionName": "续费充值"
        },
        {
            "functionId": 20005,
            "parentFunctionId": 10001,
            "functionName": "充值记录"
        },
        {
            "functionId": 20006,
            "parentFunctionId": 10001,
            "functionName": "消耗记录"
        },
        {
            "functionId": 20007,
            "parentFunctionId": 10001,
            "functionName": "邀请记录"
        },
        {
            "functionId": 30000,
            "parentFunctionId": 20000,
            "functionName": "添加链接"
        },
        {
            "functionId": 30001,
            "parentFunctionId": 20001,
            "functionName": "添加链接"
        },
        {
            "functionId": 30002,
            "parentFunctionId": 20001,
            "functionName": "提醒设置"
        },
        {
            "functionId": 30003,
            "parentFunctionId": 20001,
            "functionName": "开启/暂停"
        },
        {
            "functionId": 30004,
            "parentFunctionId": 20001,
            "functionName": "首次检测报告"
        },
        {
            "functionId": 30005,
            "parentFunctionId": 20002,
            "functionName": "评论分析"
        },
        {
            "functionId": 30006,
            "parentFunctionId": 20002,
            "functionName": "评论详情"
        },
        {
            "functionId": 30007,
            "parentFunctionId": 20008,
            "functionName": "详情变更分析"
        },
        {
            "functionId": 30008,
            "parentFunctionId": 20008,
            "functionName": "详情变更检测"
        },
        {
            "functionId": 30009,
            "parentFunctionId": 20008,
            "functionName": "备注"
        },
        {
            "functionId": 20008,
            "parentFunctionId": 10000,
            "functionName": "详情检测"
        }
    ],
    "success": true
}

代码:

const useSystemFeatures = (responseData) => {
    const objMap = Object.create(null);
    const result = new Array();
    // 用一个map装父级
    for (let i = 0; i < responseData.length; i++) {
        const feature = responseData[i];
        feature.id = uuid();
        // 顶级父级装到第一层
        if (feature.parentFunctionId === 0) {
            result.push(feature);
        }
        objMap[feature.functionId] = feature;
    }
    for (let i = 0; i < responseData.length; i++) {
        const feature = responseData[i];
        // 如果不为顶级父级则带着parentFunctionId去map里找父级
        if (feature.parentFunctionId !== 0) {
            const parentFeature = objMap[feature.parentFunctionId];
            // 如果没找到则跳过
            if (undefined === parentFeature) {
                continue;
            }
            // 如果找的是自己本身 也跳过
            if (parentFeature.functionId === feature.functionId) {
                continue;
            }
            // 以上情况都未命中那就是找到了父级 判断是否有children 有就把自己push到父级
            if (undefined === parentFeature.children) {
                parentFeature.children = [];
            }
            parentFeature.children.push(feature);
        }
    }
    return result;
}

首先封装一个组件渲染基本单元,判断是否有children,有的话就继续遍历children调用组件本身继续渲染,说明: SelectNode就是封装的组件,然后.node元素就是要渲染的节点的基本单元

<template>
  <div class="select-node">
    <div class="node">
      <el-checkbox :label="feature.functionId">{{
        feature.functionName
      }}</el-checkbox>
    </div>
    <div class="children" v-if="hasChildrenNodes(feature)">
      <SelectNode
        v-for="feature in feature.children"
        :key="feature.id"
        :feature="feature"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: "SelectNode",
  components: {
    SelectNode: () => import("../SelectNode"),
  },
  props: {
    feature: {
      type: Object,
      default: () => {},
    },
  },
  computed: {
    /**
     * @description 是否有子节点
     */
    hasChildrenNodes() {
      return (feature) => {
        return feature.children && feature.children.length;
      };
    },
  },
};
</script>

<style lang="scss" src="./index.scss" scoped>
</style>

在父组件调用组件:

<template>
  <div class="feature-select">
    <el-checkbox-group v-model="checkedList" class="select-node-wrapper">
      <SelectNode
        v-for="feature in systemFeatures"
        :key="feature.id"
        :feature="feature"
      />
    </el-checkbox-group>
  </div>
</template>

<script>
export default {
  name: "FeatureSelect",
  components: {
    SelectNode: () => import("./SelectNode"),
  },
  props: {
    systemFeatures: {
      type: Array,
      default: () => [],
    },
    functionIds: {
      type: Array,
      default: () => [],
    },
  },
  computed: {
    /**
     * @description 已选中的checkbox集合
     */
    checkedList: {
      get() {
        return this.functionIds;
      },
      set(currentFunctionIds) {
        this.$emit("update:functionIds", currentFunctionIds);
      },
    },
  },
};
</script>

<style lang="scss" src="./index.scss" scoped>
</style>

效果:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值