这里使用的是用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>
效果: