想问一下从后端得到如下所示数据,怎么转换为el-menu的三级菜单的数据结构(面试时遇到的笔试题没写出来)(语言-javascript)

后端传入的数据

list = [
  {"ID": 1,"MenuOne": "教学楼","MenuTwo": "A01教室","NoteName": "A01前"},
  {"ID": 2,"MenuOne": "教学楼","MenuTwo": "A01教室","NoteName": "A01后"},
  {"ID": 3,"MenuOne": "教学楼","MenuTwo": "A02教室","NoteName": "A02前"},
  {"ID": 4,"MenuOne": "教学楼","MenuTwo": "A02教室","NoteName": "A02后"},
  {"ID": 5,"MenuOne": "操场","MenuTwo": "跑道","NoteName": "跑道前"},
  {"ID": 6,"MenuOne": "操场","MenuTwo": "跑道","NoteName": "跑道后"},
  {"ID": 7,"MenuOne": "操场","MenuTwo": "厕所","NoteName": "厕所前"},
  {"ID": 8,"MenuOne": "操场","MenuTwo": "厕所","NoteName": "厕所后"},
  {"ID": 9,"MenuOne": "食堂","MenuTwo": "","NoteName": "食堂前"},
  {"ID": 10,"MenuOne": "食堂","MenuTwo": "","NoteName": "食堂后"},
  {"ID": 11,"MenuOne": "食堂","MenuTwo": "","NoteName": "食堂左"},
  {"ID": 12,"MenuOne": "食堂","MenuTwo": "","NoteName": "食堂右"},
]
我想要达到的结果
menu = [
  {
    id:'1',
    label:'教学楼',
    child:[
      {
        label:'A01教室',
        child:[
          {id:'1-1',label:'A01前'},
          {id:'1-2',label:'A01后'}
        ]
      },
      {
        label:'A02教室',
        child:[
          {id:'1-3',label:'A02前'},
          {id:'1-4',label:'A02后'}
        ]
      },
    ]
  },
  {
    id:'2',
    label:'操场',
    child:[
      {
        label:'跑道',
        child:[
          {id:'2-1',label:'跑道前'},
          {id:'2-2',label:'跑道后'}
        ]
      },
      {
        label:'厕所',
        child:[
          {id:'2-3',label:'厕所前'},
          {id:'2-4',label:'厕所后'}
        ]
      },
    ]
  },
  {
    id:'3',
    label:'食堂',
    child:[
      {
        label:'',
        child:[
          {id:'3-1',label:'食堂前'},
          {id:'3-2',label:'食堂后'},
          {id:'3-3',label:'食堂左'},
          {id:'3-4',label:'食堂右'}
        ]
      }
    ]
  }
]


var list = [
        { ID: 1, MenuOne: "教学楼", MenuTwo: "A01教室", NoteName: "A01前" },
        { ID: 2, MenuOne: "教学楼", MenuTwo: "A01教室", NoteName: "A01后" },
        { ID: 3, MenuOne: "教学楼", MenuTwo: "A02教室", NoteName: "A02前" },
        { ID: 4, MenuOne: "教学楼", MenuTwo: "A02教室", NoteName: "A02后" },
        { ID: 5, MenuOne: "操场", MenuTwo: "跑道", NoteName: "跑道前" },
        { ID: 6, MenuOne: "操场", MenuTwo: "跑道", NoteName: "跑道后" },
        { ID: 7, MenuOne: "操场", MenuTwo: "厕所", NoteName: "厕所前" },
        { ID: 8, MenuOne: "操场", MenuTwo: "厕所", NoteName: "厕所后" },
        { ID: 9, MenuOne: "食堂", MenuTwo: "", NoteName: "食堂前" },
        { ID: 10, MenuOne: "食堂", MenuTwo: "", NoteName: "食堂后" },
        { ID: 11, MenuOne: "食堂", MenuTwo: "", NoteName: "食堂左" },
        { ID: 12, MenuOne: "食堂", MenuTwo: "", NoteName: "食堂右" },
      ];

      let arr = [];

      list.map((item) => {
        let isHasOne = arr.findIndex((ele) => ele.label == item.MenuOne);
        if (isHasOne === -1) {
          let id = (arr.length + 1).toString();
          arr.push({
            id,
            label: item.MenuOne,
            child: [
              {
                label: item.MenuTwo,
                child: [
                  {
                    id: id + "-1",
                    label: item.NoteName,
                  },
                ],
              },
            ],
          });
        } else {
          let isHasTwo = arr[isHasOne].child.findIndex(
            (ele) => ele.label == item.MenuTwo
          );
          let sub = arr[isHasOne].child.reduce((a, b) => {
            let result = b.child.concat(a.child);
            b.child = result;
            return b;
          });
          if (isHasTwo === -1) {
            arr[isHasOne].child.push({
              label: item.MenuTwo,
              child: [
                {
                  id: arr[isHasOne].id + "-" + (sub.child.length + 1),
                  label: item.NoteName,
                },
              ],
            });
          } else {
            arr[isHasOne].child[isHasTwo].child.push({
              id: arr[isHasOne].id + "-" + (sub.child.length + 1),
              label: item.NoteName,
            });
          }
        }
      });

      console.log("arr", arr);


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script type="text/javascript">
        let list = [
            { "ID": 1, "MenuOne": "教学楼", "MenuTwo": "A01教室", "NoteName": "A01前" },
            { "ID": 2, "MenuOne": "教学楼", "MenuTwo": "A01教室", "NoteName": "A01后" },
            { "ID": 3, "MenuOne": "教学楼", "MenuTwo": "A02教室", "NoteName": "A02前" },
            { "ID": 4, "MenuOne": "教学楼", "MenuTwo": "A02教室", "NoteName": "A02后" },

            { "ID": 5, "MenuOne": "操场", "MenuTwo": "跑道", "NoteName": "跑道前" },
            { "ID": 6, "MenuOne": "操场", "MenuTwo": "跑道", "NoteName": "跑道后" },
            { "ID": 7, "MenuOne": "操场", "MenuTwo": "厕所", "NoteName": "厕所前" },
            { "ID": 8, "MenuOne": "操场", "MenuTwo": "厕所", "NoteName": "厕所后" },

            { "ID": 9, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂前" },
            { "ID": 10, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂后" },
            { "ID": 11, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂左" },
            { "ID": 12, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂右" },
        ]

        let figureList = [], zindex = 0, yindex = 0;
        list.forEach(item => {
            if (
                figureList.length > 0 &&
                figureList.some((zitem) => zitem.label == item.MenuOne)
            ) {
                let index = figureList.findIndex(
                    (sitem) => sitem.label == item.MenuOne
                );
                yindex++
                if (
                    figureList[index].child.length > 0 &&
                    figureList[index].child.some((zitem) => zitem.label == item.MenuTwo)
                ) {
                    let sindex = figureList[index].child.findIndex(
                        (sitem) => sitem.label == item.MenuTwo
                    );
                    figureList[index].child[sindex].child.push(
                        { id: `${zindex}-${yindex}`, label: item.NoteName },
                    )
                } else {
                    figureList[index].child.push(
                        {
                            label: item.MenuTwo,
                            child: [
                                { id: `${zindex}-${yindex}`, label: item.NoteName },

                            ]
                        },

                    )
                }
            } else {
                zindex++
                yindex = zindex
                figureList.push({
                    id: zindex,
                    label: item.MenuOne,
                    child: [
                        {
                            label: item.MenuTwo,
                            child: [
                                { id: `${zindex}-${yindex}`, label: item.NoteName },

                            ]
                        },

                    ]

                });
            }
        });

        console.log(figureList, '===figureList')

    </script>
</body>

</html>
  1. 写了下数据处理的代码,我想面试题的想考的是你的数据处理能力
  2. 思路是先构建hashmap,先将所有数据的层级关联给处理了,用hashmap有个好处就是,即使数据是乱序的,也能合理的找到对应关系
  3. 得到hashmap后就简单了,直接进行遍历,拿到我们的结果数据,但这个遍历如果是多层,那会有多个for循环,不够优雅,所以使用了递归,也适用于更多场景
  4. 如果直接判断item.MenuOneitem.MenuTwo等参数,也不够优雅,因为我们的层级key可能会发生变化,所以抽离了个数组,这样更灵活,也不怕需求变更和顺序调整
  5. 如有帮助请采纳~非常感谢
// input 数据
const list = [
    { "ID": 1, "MenuOne": "教学楼", "MenuTwo": "A01教室", "NoteName": "A01前" },
    { "ID": 2, "MenuOne": "教学楼", "MenuTwo": "A01教室", "NoteName": "A01后" },
    { "ID": 3, "MenuOne": "教学楼", "MenuTwo": "A02教室", "NoteName": "A02前" },
    { "ID": 4, "MenuOne": "教学楼", "MenuTwo": "A02教室", "NoteName": "A02后" },
    { "ID": 5, "MenuOne": "操场", "MenuTwo": "跑道", "NoteName": "跑道前" },
    { "ID": 6, "MenuOne": "操场", "MenuTwo": "跑道", "NoteName": "跑道后" },
    { "ID": 7, "MenuOne": "操场", "MenuTwo": "厕所", "NoteName": "厕所前" },
    { "ID": 8, "MenuOne": "操场", "MenuTwo": "厕所", "NoteName": "厕所后" },
    { "ID": 9, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂前" },
    { "ID": 10, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂后" },
    { "ID": 11, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂左" },
    { "ID": 12, "MenuOne": "食堂", "MenuTwo": "", "NoteName": "食堂右" },
]

// 处理函数
const handleData = props => {
    // 配置层级对应key
    let level = ['MenuOne', 'MenuTwo', 'NoteName'];
    // hashmap
    let map = [];
    props.forEach(tem => {
        // 建立指针
        let current = map;
        // 读取一条数据的多个key
        for (let key of level) {
            const label = tem[key];
            if (!current[label]) {
                current[label] = {
                    label: label || '',
                }
                if (key !== level[level.length - 1]) current[label].child = []
            }
            current = current[label].child;
        }
    })

    let res = [];
    // 递归处理id以及格式
    let helper = (obj, id) => {
        let i = 1;
        let tem = {
            label: obj.label,
            id
        };
        if (obj.child) {
            tem.child = []
            for (let key in obj.child) {
                tem.child.push(helper(obj.child[key], `${id}-${i++}`))
            }
        }
        return tem;
    }
    // 第一层的处理
    let i = 1;
    for (let key in map) {
        res.push(helper(map[key], i++))
    }
    return res
}
// 处理结果
console.log(handleData(list))

你好,可以定义一个模板形式进行转换,如有帮助,请采纳


<template>
  <div class="menu">
     <el-menu
      class="el-menu-vertical-demo"
      @open="handleOpen"
      @close="handleClose"
      background-color="rgb(255,255,255)"
      text-color="rgb(28,41,89)"
      router = router
      active-text-color="rgb(28,41,89)">
      <template v-for="(item, key) in menuList">
        <el-submenu :key="key" v-if="item.children && item.children.length!==0" :index="item.m_url">
          <template slot="title">
            <i :class="item.m_icon"></i>
            <span>{{ item.m_name }}</span>
          </template>
          <el-menu-item v-for="(val, index) in item.children" :index="val.m_url" :key="index">
            <template slot="title">
              <i :class="val.m_icon"></i>
              <span>{{ val.m_name }}</span>
            </template>
          </el-menu-item>
        </el-submenu>
        <el-submenu v-else :key="item.m_n_id" :index="item.m_url">
          <template slot="title">
            <i :class="item.m_icon"></i>
            <span>{{ item.m_name }}</span>
          </template>
        </el-submenu>
      </template>
    </el-menu>
  </div>
</template>

<script>
import { mapActions } from 'vuex';
  export default {
    name: "asideItem",
    data(){
      return{
        router: true,
        isCollapse: true,
        label: false,
        menuList: []
      }
    },
    mounted() {
      this.getMenu()
    },
    methods: {
      ...mapActions([
        'getMenuList'
      ]),
      handleOpen(key, keyPath) {
        console.log(key, keyPath);
      },
      handleClose(key, keyPath) {
        console.log(key, keyPath);
      },
      labelChange: function() {
        console.log(this.label);
      },
      getMenu: function() { // 从后台获取菜单列表
        this.getMenuList().then(res => {
          if(res.errno === 0) {
            this.menuList = res.data
          } else {
            this.$message.error(res.data)
          }
        }).catch(error => { this.$message.error(error) })
      }
    }
  };
</script>