Vue中使用Element 以el-menu导航菜单形式展示Tree树形结构

目的
项目分为全局路由如登录页面,404页面之类的和由侧边栏menu控制跳转的子路由页面主要是业务页面。页面子页面放入views文件夹下,将自动读入注册成route,配置文件主要用于生成树形menu侧边栏。建议配合项目结构进行阅读效果更佳

效果
Vue中使用Element 以el-menu导航菜单形式展示Tree树形结构_第1张图片
项目结构
Vue中使用Element 以el-menu导航菜单形式展示Tree树形结构_第2张图片
子页面配置文件
将根据以下配置文件生成树形menu导航栏

 export default [
    {
     
        url: "/page1",
        meta: {
      title: '页面1', requiresAuth: false },
        children: [
            {
     
                url: "/page2",
                meta: {
     
                    requiresAuth: false,
                    title: "页面2"
                },
                children: [
                    {
     
                        url: "/page3",
                        meta: {
     
                            requiresAuth: false,
                            title: "页面3"
                        }
                    },
                ],
            },
        ],
    },
    {
     
        url: "/page4",
        meta: {
      title: '页面4', requiresAuth: false }
    }
]

全局页面配置文件

export default [
    {
     
        url: "/login",
        meta: {
      title: '登录', requiresAuth: false }
    },
]

侧边栏模板组件

sideBar组件

 <template>
  <div class="side-bar-wrapper" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave">
    <el-aside class="index-aside" :width="isSideBarExpand?'65px':'150px'">
      <div class="title_banner"></div>
      <el-menu
        class="aside-menu"
        :collapse="isSideBarExpand"
        ref="sideBar"
        :default-active="onRoutes"
        text-color="#a5a5a5"
        active-text-color="#00c1de"
        background-color="#414549"
        unique-opened
        menu-trigger="click"
        :collapse-transition="collapseTransition"
      >
        <template v-for="(item) in menuList">
          <el-menu-item
            v-if="!item.list"
            :index="item.route"
            :key="item.route"
            @click="barHref(item.route)"
          >
            <icon-svg
              :icon-class="item.icon"
              :class="{
     
                'avtive_bar_icon':item.route == onRoutes,
                'bar_icon':item.route != onRoutes
              }"
            />
            <span slot="title" class="bar_title">{
     {
     item.title}}</span>
          </el-menu-item>
          <TreeMenu :key="item.route+'s'" v-if="item.list" :item="item"></TreeMenu>
        </template>
      </el-menu>
    </el-aside>
  </div>
</template>

<script>
import page from "@/config/router/pages.js";
import TreeMenu from "./menu";

export default {
     
  name: "sideBar",
  created() {
     
    this.getCachePage();
  },
  components: {
      TreeMenu },
  data() {
     
    return {
     
      isCollapse: false,
      isSideBarExpand: true,
      collapseTransition: false,
      menuList: []
    };
  },
  methods: {
     
    async getCachePage() {
     
      this.menuList = this.creatMenu(page);
    },
    /* 
    保存被打开的侧边栏的状态
    */
    onMouseEnter() {
     
      this.isSideBarExpand = false;
      let menuRoute = "";
      this.menuList.forEach(x => {
     
        if (x.list && x.list.length > 0) {
     
          if (
            x.list.find(y => {
     
              return y.route === this.onRoutes;
            })
          ) {
     
            menuRoute = x.route;
          }
        }
      });
      if (menuRoute) this.$refs.sideBar.open(menuRoute);
    },
    onMouseLeave() {
     
      this.isSideBarExpand = true;
    },
    showSideBar() {
     
      this.isCollapse = !this.isCollapse;
    },
    creatMenu(list) {
     
      var menuList = [];
      list.forEach(s => {
     
        let menu = {
     
          title: s.meta.title,
          icon: s.url.replace("/", ""),
          index: s.url.replace("/", ""),
          route: s.url,
          list:
            s.children && s.children.length > 0
              ? this.creatMenu(s.children)
              : undefined
        };
        menuList.push(menu);
      });
      return menuList;
    },
    barHref(s) {
     
      if(s==this.onRoutes)return
      this.$router.push({
      path: s });
    }
  },
  computed: {
     
    onRoutes() {
     
      return this.$route.path;
    }
  }
};
</script>
<style lang="scss" >
.side-bar-wrapper {
     
  height: 100%;
  z-index: 20;
}
.title_banner {
     
  width: 100%;
  height: 50px;
}
.side-bar-wrapper .index-aside {
     
  overflow: hidden;
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 20;
  // padding-top: 20px;
  background: #414549;
  -webkit-transition: width 0.3s;
  transition: width 0.3s;
  .el-menu {
     
    border-right: none;
    .el-menu-item {
     
      // padding-left: 20px !important;
    }
  }
}
.side-bar-wrapper .index-aside .aside-menu {
     
  height: 100%;
}
.side-bar-wrapper .index-aside .aside-menu .nav-icon {
     
  width: 20px;
  height: 20px;
}
.side-bar-wrapper .index-aside .el-menu {
     
  overflow: hidden;
}
.bar_icon {
     
  color: #fff;
}
.avtive_bar_icon {
     
  color: #00c1de;
}
.bar_title {
     
  margin-left: 5px;
}
</style>

menu组件
主要用于树形嵌套结构

<template>
  <el-submenu
    v-if="item.title&&item.list"
    :index="item.route"
    :key="item.route"
    :show-timeout="0"
    :hide-timeout="0"
  >
    <template slot="title">
      <div>
        <icon-svg
          :icon-class="item.icon"
          :class="{
     
                'avtive_bar_icon':inParentPage(item.list,onRoutes),
                'bar_icon':!inParentPage(item.list,onRoutes)
              }"
        />
        <span slot="title" style="margin-left:3px">{
     {
     item.title}}</span>
      </div>
    </template>
    <template v-for="(it) in item.list">
      <el-menu-item v-if="!it.list" :index="it.route" :key="it.route" 	  @click="barHref(it.route)">
        <icon-svg
          :icon-class="it.icon"
          :class="{
     
                'avtive_bar_icon':it.route == onRoutes,
                'bar_icon':it.route != onRoutes
              }"
        />
        <span slot="title" class="bar_title">{
     {
     it.title}}</span>
      </el-menu-item>
      <TreeMenu :key="it.route+'s'" v-if="it.list" :item="it"></TreeMenu>
    </template>
  </el-submenu>
</template>

<script>
export default {
     
  props: ["item"],
  name: "TreeMenu",
  methods: {
     
    barHref(s) {
     
      if(s==this.onRoutes)return
      this.$router.push({
      path: s });
    },
    inParentPage(list,page){
     
      let flag = false
      function loop(pages,p){
     
        for(let i = 0 ;i<pages.length;i++){
     
          if(pages[i].route==p){
     
            flag = true;
            break
          }
          if(pages[i].list){
     
            loop(pages[i].list,page)
          }
        }
      }
      loop(list,page)
      return flag
    },
  },
  computed: {
     
    onRoutes() {
     
      return this.$route.path;
    }
  }
};
</script>

<style scoped lang='scss'>
.bar_icon {
     
  color: #fff;
}
.avtive_bar_icon {
     
  color: #00c1de;
}
.bar_title {
     
  margin-left: 5px;
}
</style>

结合Element 布局组件,生成主页面

 <template>
  <el-container class="content">
    <side-bar></side-bar>
    <el-container class="main-container">
      <el-header style="height:50px">
        <common-header ref="commomHeader"></common-header>
      </el-header>
      <el-main>
        <router-view :key="key"></router-view>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
import sideBar from "./sideBar.vue";
import commonHeader from "./commonHeader.vue";
export default {
     
  components: {
      sideBar, commonHeader },
  computed: {
     
    key() {
     
      return this.$route.name !== undefined
        ? this.$route.name + +new Date()
        : this.$route + +new Date();
    }
  }
};
</script>

<style lang='scss'>
.el-container {
     
  position: relative;
}
.el-header {
     
  padding: 0px;
}
.main-container{
     
  margin-left: 65px;
}
</style>

vue router 配置,读取页面配置文件自动注册路由

import page from './pages.js'
import globalPage from './globalPages.js'
import Router from 'vue-router'
const vueRouter = new Router({
     
    mode: 'history',
    routes: [...getRouteList(globalPage)]
})
vueRouter.addRoutes(
    [{
     
        path: '/',
        name: 'index',
        component: resolve => require(["@/globalViews/main/main.vue"], resolve),
        children: [...getRouteList([...page])],
        // redirect: page[0].url // 默认index重定向到home页面
    }
    ]
)
// 全局钩子,单独页面钩子在配置项单独设置
vueRouter.beforeEach((to, from, next) => {
     
    if (to.meta.requiresAuth && !localStorage.getItem("Token")) {
     
        console.warn('没有权限,跳转到登录')
        next('/login')
    } else {
     
        next()
    }

})
// 根据配置生成route对象集合
function getRouteList(routes) {
     
    let res = []
    let hander = function (list) {
     
        list.forEach((s) => {
     
            if (s.children) {
     
                hander(s.children)
            }
            if (s.url) {
     
                let route = {
     
                    path: s.url,
                    component: resolve => require(["@/views" + s.url + s.url + ".vue"], resolve),
                    name: s.url.replace('/', ''),
                    meta: s.meta
                }
                res.push(route)
            }
        })
    }
    hander(routes)
    // console.log(res)
    return res
}

export default vueRouter;

将Router配置注入Vue构造

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import router from '@/config/router/index'

Vue.config.productionTip = false
Vue.use(VueRouter)
new Vue({
     
  router,
  render: h => h(App),
}).$mount('#app')


总结
还是react清晰好使
https://blog.csdn.net/weixin_39168678/article/details/107315893

你可能感兴趣的:(前端常用开发记录,vue)