1. 程式人生 > 實用技巧 >Vue + Node + Element UI 專案(十)_製作動態導航欄

Vue + Node + Element UI 專案(十)_製作動態導航欄

之前的導航欄是靜態寫死的,現在我們需要將其改為動態的:路由修改後,導航欄也隨之修改,頁面根據路由進行跳轉。

分析程式碼

原SideBar.vue中導航欄程式碼

<el-menu
      default-active="3-1"
      class="el-menu-vertical-demo"
      @open="isOpen"
      @close="isClose"
      :collapse="isCollapse">

      <el-menu-item index="1">
        <div class="nav-first">
          <i class="el-icon-setting"></i>
          <span slot="title">首頁</span>
        </div>
      </el-menu-item>

      <el-submenu index="2">
          <template slot="title">
            <div class="nav-first">
              <i class="el-icon-location"></i>
              <span slot="title">導航一</span>
            </div>
          </template>
          <el-menu-item index="2-1">
            <span slot="title"><span class="dot"></span>選項一</span>
          </el-menu-item>
          <el-menu-item index="2-2">
            <span slot="title"><span class="dot"></span>選項2</span>
          </el-menu-item>
          <el-menu-item index="2-3">
            <span slot="title"><span class="dot"></span>選項一</span>
          </el-menu-item>
          <el-submenu index="2-4">
            <span slot="title"><span class="dot"></span>選項4</span>
            <el-menu-item index="1-4-1">選項1</el-menu-item>
          </el-submenu>
        </el-submenu>

      <el-submenu index="3">
        <template slot="title">
          <div class="nav-first">
            <i class="el-icon-location"></i>
            <span slot="title">測試頁面</span>
          </div>
        </template>
        <el-menu-item index="3-1" @click="$router.push('/3-1')">
          <span slot="title"><span class="dot"></span>testAxios</span>
        </el-menu-item>
        <el-menu-item index="3-2" @click="$router.push('/3-2')">
          <span slot="title"><span class="dot"></span>testMock</span>
        </el-menu-item>
        <el-menu-item index="3-3" @click="$router.push('/3-3')">
          <span slot="title"><span class="dot"></span>主題測試</span>
        </el-menu-item>
      </el-submenu>

      <!-- <el-menu-item index="4">
        <div class="nav-first">
          <i class="el-icon-document"></i>
          <span slot="title">404</span>
        </div>
      </el-menu-item> -->

        <el-menu-item index="4" disabled>
          <div class="nav-first">
            <i class="el-icon-document"></i>
            <span slot="title">導航三</span>
          </div>
        </el-menu-item>
        <el-menu-item index="5">
          <div class="nav-first">
            <i class="el-icon-setting"></i>
            <span slot="title">導航四</span>
          </div>
        </el-menu-item>

    </el-menu>

分析程式碼得:

每一級導航都有不一樣的寫法,那我們可以設定一些屬性來控制不同級數的導航的不同寫法:

並且有些路由比如Login不需要在導航欄顯示,所以新增一個屬性:isHidden,當isHidden未true時,不在導航欄顯示。
導航欄中顯示的文字和一級導航需要的圖示可以通過新增一個物件meta來控制。

確定路由的寫法如下:

  • 不需要在導航欄顯示
    {
      path: '/', //http://localhost:8081/#/
      name: 'Home',  
      component: Home, //import的元件名
      isHidden:true, //不在導航列表中顯示
      redirect: '/menu1', //當路由未匹配時重定向,可作初始化顯示頁面設定
    },
    {
      path: '/Login', 
      name: 'Login',
      component: Login,
      isHidden:true //不在導航列表中顯示
    },
  • 一級選單
{
      path: '/menu3',
      component: Home,   //是Home頁面的佈局
      name: 'menu3',   
      redirect:'/menu3-1', //當路由未匹配時重定向,可作初始化顯示頁面設定
      meta: {
        title: '二級導航menu3',
        icon: 'el-icon-document'
      },
      children: [
        {
            path: '/menu3-1',
            name: 'menu3-1',
            meta: {
                title: 'menu3-1'
            },
            component: resolve => require(['@/views/uiMenu/Ui.vue'], resolve),
        }
      ]
    }

這裡說明一下為什麼要這樣寫,而不能直接像前面——不在導航欄顯示 的那樣寫,因為一級導航頁面需要通過Home頁面開啟,若按照前面的寫法,是重新開啟一個新頁面,比如登入頁面,佈局和Home完全無關。

  • 二級選單
{
      path: '/menu2',
      component: Home,
      name: 'menu2',
      leaf:true,//有二級路由
      meta: {
        title: '測試頁面',
        icon: 'el-icon-location'
      },
      children: [
        {
            path: '/menu2-1',
            name: 'menu2-1',
            meta: {
                title: 'TestAxios'
            },
            component: resolve => require(['@/views/testPages/TestAxios.vue'], resolve),
        },
        {
            path: '/menu2-2',
            name: 'menu2-2',
            meta: {
                title: 'TestMock'
            },
            component: resolve => require(['@/views/testPages/TestMock.vue'], resolve),
        },
        {
          path: '/menu2-3',
          name: 'menu2-3',
          meta: {
              title: '主題測試'
          },
          component: resolve => require(['@/views/testPages/TestUI.vue'], resolve),
        }
      ]
    },

一級和二級的區別在於二級添加了有二級選單這個屬性“ leaf:true ”, 少了重新定向這個“ redirect:'/menu3-1' ”,沒有這個屬性

  • 三級選單
    {
      path: '/menu1',
      component: Home,
      name: 'menu1',
      leafThree: true,//有三級路由
      meta: {
        title: '三級導航1',
        icon: 'el-icon-location'
      },
      children: [
        {
          path: '/menu1-1',
          name: 'menu1-1',
          meta: {
              title: '三級導航1-1'
          },
          component: Mrouter,
          leaf: true,//有二級路由
          children:[
            {
                path: '/menu1-1-1',
                name: 'menu1-1-1',
                meta: {
                    title: '三級導航1-1-1'
                },
                component: resolve => require(['@/views/testPages/menu1/Menu1-1-1.vue'], resolve),
            }
          ]
        },

        {
          path: '/menu1-2',
          name: 'menu1-2',
          meta: {
              title: '三級導航1-2'
          },
          component: resolve => require(['@/views/testPages/menu1/Menu1-2.vue'], resolve),
        }
      ]
    },

二級和三級的區別在於一級目錄添加了有三級選單這個屬性“ leafThree:true ”, 二級children中多了“ leaf: true ” 和 在component處修改為“ component: Mrouter ”,並新增children

修改 router/index.js

import Vue from 'vue'
import Router from 'vue-router'

//頁面佈局
import Home from '@/views/Home'  //頁面佈局
import Mrouter from '@/views/common/main/Mrouter'  //路由承載公共元件

//單個頁面
import NotFound from '@/views/err/404'  //404頁面
import Login from '@/views/login/Login' //登入頁面



Vue.use(Router)

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/', //http://localhost:8081/#/
      name: 'Home',  
      component: Home, //import的元件名
      isHidden:true, //不在導航列表中顯示
      redirect: '/menu1', //當路由未匹配時重定向,可作初始化顯示頁面設定
    },
    {
      path: '/Login', 
      name: 'Login',
      component: Login,
      isHidden:true //不在導航列表中顯示
    },
    {
      path: '/404', 
      name: 'NotFound',
      component: NotFound,
      isHidden:true//不在導航列表中顯示
    },

    {
      path: '/menu1',
      component: Home,
      name: 'menu1',
      leafThree: true,//有三級路由
      meta: {
        title: '三級導航1',
        icon: 'el-icon-location'
      },
      children: [
        {
          path: '/menu1-1',
          name: 'menu1-1',
          meta: {
              title: '三級導航1-1'
          },
          component: Mrouter,
          leaf: true,//有二級路由
          children:[
            {
                path: '/menu1-1-1',
                name: 'menu1-1-1',
                meta: {
                    title: '三級導航1-1-1'
                },
                component: resolve => require(['@/views/testPages/menu1/Menu1-1-1.vue'], resolve),
            }
          ]
        },

        {
          path: '/menu1-2',
          name: 'menu1-2',
          meta: {
              title: '三級導航1-2'
          },
          component: resolve => require(['@/views/testPages/menu1/Menu1-2.vue'], resolve),
        }
      ]
    },

    {
      path: '/menu2',
      component: Home,
      name: 'menu2',
      leaf:true,//有二級路由
      meta: {
        title: '測試頁面',
        icon: 'el-icon-location'
      },
      children: [
        {
            path: '/menu2-1',
            name: 'menu2-1',
            meta: {
                title: 'TestAxios'
            },
            component: resolve => require(['@/views/testPages/TestAxios.vue'], resolve),
        },
        {
            path: '/menu2-2',
            name: 'menu2-2',
            meta: {
                title: 'TestMock'
            },
            component: resolve => require(['@/views/testPages/TestMock.vue'], resolve),
        },
        {
          path: '/menu2-3',
          name: 'menu2-3',
          meta: {
              title: '主題測試'
          },
          component: resolve => require(['@/views/testPages/TestUI.vue'], resolve),
        }
      ]
    },

    {
      path: '/menu3',
      component: Home,
      name: 'menu3',   
      redirect:'/menu3-1', //當路由未匹配時重定向,可作初始化顯示頁面設定
      meta: {
        title: '二級導航menu3',
        icon: 'el-icon-document'
      },
      children: [
        {
            path: '/menu3-1',
            name: 'menu3-1',
            meta: {
                title: 'menu3-1'
            },
            component: resolve => require(['@/views/uiMenu/Ui.vue'], resolve),
        }
      ]
    }




  ]
})


router.beforeEach((to, from, next) => {
  //登入介面登入成功之後,會把使用者資訊儲存在會話
  //存在時間位會話生命週期,頁面關閉即失效。
  let user = sessionStorage.getItem('user');
  if(to.path == '/login') {
    //如果是訪問登入介面,如果使用者會話資訊存在,代表已經登入過,跳轉到主頁
    if(user) {
      next({ path: '/'})
    } else {
      next()
    }
  } else {
    //如果訪問非登入頁面,且使用者會話資訊不存在,代表為登入,則跳轉到登入頁面
    if(!user) {
      next({ path: '/login' })
    } else{
      next()
    }
  }
})

export default router

修改sideBar.vue中的導航欄程式碼

    <el-menu
      router
      default-active="$route.path"
      class="el-menu-vertical-demo"
      @open="isOpen"
      @close="isClose"
      :collapse="isCollapse">

      <template v-for="(item,index) in routes" v-if="!item.isHidden" >
          <!-- 一級選單 -->
        <el-menu-item v-if="!item.leaf && !item.leafThree && item.children.length>0" :index="item.path"> 
          <div class="nav-first">
            <i :class="item.meta.icon"></i>
            <span slot="title">{{item.meta.title}}</span>
          </div>
        </el-menu-item>

        <!-- 二級選單 -->
        <el-submenu :index="index+''" v-if="item.leaf">
            <template slot="title">
              <div class="nav-first">
                <i :class="item.meta.icon"></i>
                <span>{{item.meta.title}}</span>
              </div>
            </template>
            <el-menu-item v-for="child in item.children" :index="child.path" v-if="!child.isHidden"  :key="child.path">
              <span slot="title"><span class="dot"></span>{{child.meta.title}}</span>
            </el-menu-item>
        </el-submenu>

        <!-- 三級選單 -->
        <el-submenu :index="index+''" v-if="!item.leaf && item.leafThree">
            <template slot="title">
              <div class="nav-first">
                <i :class="item.meta.icon"></i>
                <span>{{item.meta.title}}</span>
              </div>
            </template>
            <el-submenu v-for="child in item.children" :index="child.path" :key="child.path" v-if="child.leaf">
              <span slot="title"><span class="dot"></span>{{child.meta.title}}</span>
              
              <el-menu-item v-for="childThree in child.children" :index="childThree.path" :key="childThree.path">
                <span>{{childThree.meta.title}}</span>
              </el-menu-item>

            </el-submenu>
            <el-menu-item v-for="child in item.children" :index="child.path" v-if="!child.isHidden && !child.leaf"  :key="child.path">
              <span slot="title"><span class="dot"></span>{{child.meta.title}}</span>
            </el-menu-item>
        </el-submenu>
      </template>



    </el-menu>

並新增如下程式碼:

重新整理頁面,發現修改成功!並且訪問正常。

但是
看著麵包屑中英文感覺很不爽,想改成和導航欄一樣的文字。so,接著改:

打開面包屑元件並修改“ item.name ” ,將其改為 “ item.meta.title ”:

檢視頁面,發現修改成功!

參考文獻

vue&Element-ui實現的導航選單:https://blog.csdn.net/lucynie/article/details/100172281