Vue开发实例(九)动态路由实现左侧菜单导航

news2024/11/15 5:19:38

之前在【Vue开发实例(六)实现左侧菜单导航】文中实现了菜单的导航,本篇是在那个基础上改造的。

动态路由实现左侧菜单导航

  • 一、动态菜单创建
  • 二、根据菜单数据来创建路由
  • 三、添加路由已加载标记,省的每次点击菜单都要加载

一、动态菜单创建

假如我定义了3条路由,分别是 ‘/index/menu1’,‘/index/menu2’,‘/index/menu3’
但当前登录的用户只有 ‘/index/menu1’,‘/index/menu2’ 两条路由的权限,如果按照【Vue开发实例(六)实现左侧菜单导航】的做法,可以直接在浏览器输入’/index/menu3’ 这条路由地址来访问,这显然是不对的,于是我们就需要动态路由。

在前文中,router/index.js下方的3条子路由,假设后端只返回menu1和menu2这2条,也就是这路由,我们只需动态创建2条即可。
在这里插入图片描述

  1. 原来的 menu_data 使用mockjs来返回,模拟后台查询菜单数据返回
    • 在mockjs中定义对象的 /post/menuList 路径get请求
    • 返回参数中除了原来的 name、icon、path 增加了component,用于定义跳转路径。

mock/index.js代码

Mock.mock('/post/menuList', 'get', function () {
  const menu_data = [
    {
      name: '一级菜单1',
      icon: 'el-icon-location',
      path: '/index/menu1',
      component: 'Main1'
    },
    {
      name: '一级菜单2',
      icon: 'el-icon-document',
      path: '/index/menu2',
      component: 'Main2'
    }
  ]
  return {
    menu_data
  }
});
  1. 修改store/index.js,全部参考代码如下
    在这里插入图片描述
import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './module/moduleA.js';
import moduleB from './module/moduleB.js';

Vue.use(Vuex)

const state = {
  username: '牛牛',
  userState: 0,
  menu_data: []
}
const mutations = {
  setUser(state, name) {
    state.username = name
  },
  setUserState(state, data) {
    state.userState += data
  },
  setMenuData(state, data) {
    state.menu_data = data
  },
}
const getters = {
  getUserState(state) {
    let data;
    if (state.userState == 0) {
      data = '无效'
    } else {
      data = state.userState + '级'
    }
    return data;
  }
}
const modules = {
  a: moduleA,
  b: moduleB
}

export default new Vuex.Store({
  state,
  mutations,
  getters,
  modules
})
  1. router/index.js 里面使用方法 beforeEach 来获取数据,并提交到store

注意:

  • 不要忘记引入axios和store的内容
import axios from "axios";
import store from "@/store/index.js";

在这里插入图片描述

import VueRouter from "vue-router"
import Index from "@/components/Index";
import axios from "axios";
import store from "@/store/index.js";

const routes = [
    //一级路由
    {
        path: '/index',
        name: 'index',
        component: Index,
        redirect: 'index/Main',
        //路由嵌套
        children:[
            {path: '/index/Main',component: () => import('@/components/Main/index.vue')},
            {path: '/index/menu1',component: () => import('@/components/Main/Main1.vue')},
            {path: '/index/menu2',component: () => import('@/components/Main/Main2.vue')},
            {path: '/index/menu3',component: () => import('@/components/Main/Main3.vue')}
        ]
    }
]
const router = new VueRouter({
    mode:'history',
    routes
})
router.beforeEach((to, from, next)=>{
    next();
    axios.get('/post/menuList').then(res=>{
         store.commit('setMenuData',res.data.menu_data)
    });
})
export  default router;
  1. Aside.vue 代码中,data里面的属性menu_data不能直接返回了,需通过computed来返回,并且返回的值是从store里面获取的

Aside.vue 参考代码如下

<template>
  <div style="height: 100%">
    <el-menu
      background-color="#545c64"
      text-color="#ffffff"
      active-text-color="#ffd04b"
      class="el-menu-vertical-demo"
      router
    >
      <el-menu-item
        :index="item.path"
        v-for="item in menu_data"
        :key="item.name"
      >
        <i :class="item.icon"></i>{{ item.name }}
      </el-menu-item>
    </el-menu>
  </div>
</template>

<script>
export default {
  name: "Aside",
  data() {
    return {};
  },
  computed: {
    menu_data: {
      get() {
        return this.$store.state.menu_data;
      },
    },
  },
};
</script>

<style scoped>
.el-icon-location,
.el-icon-document,
.el-icon-setting {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
</style>

页面效果
在这里插入图片描述

此时菜单确实只有2个菜单,点击菜单也能对应访问到路由menu1和menu2,但是当我们在地址栏输入 menu3的时候,也能访问,这显然是不对的,因为我们的路由是静态写死的,这里肯定是不合理的,所以需要动态来修改一下。

在这里插入图片描述

二、根据菜单数据来创建路由

目前的路由写法

const routes = [
    //一级路由
    {
        path: '/index',
        name: 'index',
        component: Index,
        redirect: 'index/Main',
        //路由嵌套
        children:[
            {path: '/index/Main',component: () => import('@/components/Main/index.vue')},
            {path: '/index/menu1',component: () => import('@/components/Main/Main1.vue')},
            {path: '/index/menu2',component: () => import('@/components/Main/Main2.vue')},
            {path: '/index/menu3',component: () => import('@/components/Main/Main3.vue')}
        ]
    }
]

针对上面的情况,我们可以考虑,通过菜单取到的数据,动态添加这个路由,而不是直接写死。

说干就干!!!

  1. 先将router/index.js这3条路由代码删除
const routes = [
    //一级路由
    {
        path: '/index',
        name: 'index',
        component: Index,
        redirect: 'index/Main',
        //路由嵌套
        children:[
            {path: '/index/Main',component: () => import('@/components/Main/index.vue')},
        ]
    }
]
  1. router/index.js 中创建添加动态路由的方法 buildRouter
let oRouters = router.options.routes;
const buildRouter = () => {
    let data = store.state.menu_data;
    data.forEach(item => {
        let new_router = {
            path: item.path,
            component: () => import('../components/Main/' + item.component + '.vue')
        }
        oRouters[0].children.push(new_router);
    })
    router.addRoutes(oRouters)
}
  1. 在创建动态菜单的同时调用这个函数,修改 router/index.js
router.beforeEach((to, from, next)=>{
    next();
    axios.get('/post/menuList').then(res=>{
         store.commit('setMenuData',res.data.menu_data);

        //动态创建路由
        buildRouter();
    });
})

页面展示,点击访问 index/menu1index/menu2正常
在这里插入图片描述

访问 index/menu3 就不会出现页面内容
在这里插入图片描述
全部参考代码

router/index.js

import VueRouter from "vue-router"
import Index from "@/components/Index";
import axios from "axios";
import store from "@/store/index.js";

const routes = [
    //一级路由
    {
        path: '/index',
        name: 'index',
        component: Index,
        redirect: 'index/Main',
        //路由嵌套
        children: [
            { path: '/index/Main', component: () => import('@/components/Main/index.vue') },
        ]
    }
]

const router = new VueRouter({
    mode: 'history',
    routes
})

let oRouters = router.options.routes;
const buildRouter = () => {
    let data = store.state.menu_data;
    data.forEach(item => {
        let new_router = {
            path: item.path,
            component: () => import('../components/Main/' + item.component + '.vue')
        }
        oRouters[0].children.push(new_router);
    })
    router.addRoutes(oRouters)
}

router.beforeEach((to, from, next) => {
    next();
    axios.get('/post/menuList').then(res => {
        store.commit('setMenuData', res.data.menu_data);

        //动态创建路由
        buildRouter();
    });
})

export default router;

三、添加路由已加载标记,省的每次点击菜单都要加载

  1. 修改 store/index.js,在store.js的state添加 属性isLoadRoute: false
    在这里插入图片描述
  2. router/index.js 添加路由的 router.beforeEach 稍作修改
    在这里插入图片描述

store和router的相关代码如下

store/index.js代码

import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './module/moduleA.js';
import moduleB from './module/moduleB.js';

Vue.use(Vuex)

const state = {
  username: '牛牛',
  userState: 0,
  menu_data: [],
  isLoadRoute: false,
}
const mutations = {
  setLoadRoute(state, data) {
    state.isLoadRoute = data
  },
  setUser(state, name) {
    state.username = name
  },
  setUserState(state, data) {
    state.userState += data
  },
  setMenuData(state, data) {
    state.menu_data = data
  },

}
const getters = {
  getUserState(state) {
    let data;
    if (state.userState == 0) {
      data = '无效'
    } else {
      data = state.userState + '级'
    }
    return data;
  }
}
const modules = {
  a: moduleA,
  b: moduleB
}

export default new Vuex.Store({
  state,
  mutations,
  getters,
  modules
})

router/index.js代码

import VueRouter from "vue-router"
import Index from "@/components/Index";
import axios from "axios";
import store from "@/store/index.js";

const routes = [
    //一级路由
    {
        path: '/index',
        name: 'index',
        component: Index,
        redirect: 'index/Main',
        //路由嵌套
        children: [
            { path: '/index/Main', component: () => import('@/components/Main/index.vue') },
        ]
    }
]

const router = new VueRouter({
    mode: 'history',
    routes
})

let oRouters = router.options.routes;
const buildRouter = () => {
    let data = store.state.menu_data;
    data.forEach(item => {
        let new_router = {
            path: item.path,
            component: () => import('../components/Main/' + item.component + '.vue')
        }
        oRouters[0].children.push(new_router);
    })
    router.addRoutes(oRouters)
}

router.beforeEach((to, from, next) => {
    //判断路由是否已经加载过
    let isLoadRoute = store.state.isLoadRoute;
    if (!isLoadRoute) {
        axios.get('/post/menuList').then(res => {
            store.commit('setMenuData', res.data.menu_data);
            //动态创建路由
            buildRouter();
            //设置已经加载过的标记
            store.commit("setLoadRoute", true);
        });
    }
    next();
})

export default router;

此时点击菜单就不会重复加载了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1486813.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vscode安装,ssh插件与配置

原因 发现很多新人在练习linux&#xff0c;可是只有windows机的时候&#xff0c;一般都是下载虚拟机&#xff0c;然后在虚拟机上安装ubuntu等linux平台。每次需要在linux中写代码&#xff0c;就打开ubuntu&#xff0c;然后在终端上用vim写代码&#xff0c;或者先编辑代码文本&…

51单片机-(中断系统)

51单片机-&#xff08;中断系统&#xff09; 了解51单片机中断系统、中断源、中断响应条件和优先级等&#xff0c;通过外部中断0实现按键控制LED亮灭为例理解中断工作原理和编程实现过程。 1.中断系统结构 89C51/52的中断系统有5个中断源 &#xff0c;2个优先级&#xff0c;…

Elasticsearch:如何创建搜索引擎

作者&#xff1a;Jessica Taylor 搜索引擎是生活中我们认为理所当然的事情之一。 每当我们寻找某些东西时&#xff0c;我们都会将一个单词或短语放入搜索引擎&#xff0c;就像魔术一样&#xff0c;它会为我们提供一个匹配结果列表。 现在可能感觉不那么神奇了&#xff0c;因为这…

linux-fork习题

通过fork产生子进程后&#xff0c;在以下子进程中发生改变的时候不会引起父进程中相应的改变的有&#xff08;&#xff09; A 文件指针 B 局部变量 C 全局变量 D 静态变量 答案应该是无答案 linux下父进程创建子进程后&#xff0c;子进程会复制父进程的用户层空间的数据…

安装Docker及DockerCompose

0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道…

1. vue3-环境准备

1、安装node.js 如果开发环境上面没有安装node.js&#xff0c;需要到node.js官方网站下载node.js。下载安装后&#xff0c;可以通过npm --version查看nodejs版本 2. 开发工具 开发工具建议使用vscode

word使用bib添加参考文献

文章目录 安装TexLive安装bibtex4word使用在word中添加参考文献使用bibtex4word在word中添加参考文献设置参考文献格式为毕业论文格式 参考 安装TexLive 从下载地址下载镜像iso文件texlive2023.iso双击打开iso镜像文件运行 install-tl-windows.bat点击安装非常非常非常耐心地安…

一个教材上的CMS网站源码在Linux服务器上登录时验证码正常,但在windows下不能正常显示

一个教材上的CMS网站源码在Linux服务器上登录时验证码正常&#xff0c;但在windows下不能正常显示。 在linux服务器上能正常显示。显示界面如下所示&#xff1a;

第十篇:复习maven

文章目录 一、什么是Maven1. 依赖管理2. 统一项目结构3. 项目构建4. 依赖的仓库 二、IDEA集成Maven1. Maven简单的安装和配置2. 配置Maven环境3. 创建Maven项目4. Maven坐标4. 导入Maven项目 三、依赖管理1. 依赖配置2. 依赖传递3. 依赖范围4. 生命周期 四、小结 一、什么是Mav…

机器学习-面经

经历了2023年的秋招&#xff0c;现在也已经入职半年了&#xff0c;空闲时间将面试中可能遇到的机器学习问题整理了一下&#xff0c;可能答案也会有错误的&#xff0c;希望大家能指出&#xff01;另外&#xff0c;不论是实习&#xff0c;还是校招&#xff0c;都祝福大家能够拿到…

《UE5_C++多人TPS完整教程》学习笔记25 ——《P26 游戏项目创建(Project Creation)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P26 游戏项目创建&#xff08;Project Creation&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译者…

【Linux信号】

目录 信号是什么Linux通过kill -l查看指令 信号的产生signal系统调用捕捉信号键盘产生信号系统调用产生信号进程异常产生信号软件条件发送信号 Code Dump信号保存信号抵达信号产生到信号抵达之间的状态叫信号未决。进程可以对信号进行阻塞使用sigprocmask()系统调用接口阻塞blo…

设计模式(九)模版方法模式

请直接看原文:设计模式&#xff08;九&#xff09;模版方法模式_模板方法模式的优缺点-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- 1.模版方法模式简介 模版方法模式介…

【架构笔记2】设计不足和过度设计

复杂系统问题设计中有两类现象需要引起关注&#xff1a;设计不足和过度设计&#xff0c;通常第一种比较常见&#xff0c;第二种则也是一种灾难。当然我认为他们都可以被优化&#xff0c;如果用正确的流程引导&#xff0c;在框架模板的限定下放飞&#xff0c;就像教养孩子有个观…

Git实战(1)

一, git log 查看提交日志情况 根据 commitId进行版本回退 git reset --hard commitId(commitId可以是一部分,不用完整的ID) 只输出一行信息: git log --pretty=oneline 快速回退: git reset --hard HEAD^ 回退到上一个版本 git reset --hard HEAD^^ 回退到上上个版本 如果…

力扣74. 搜索二维矩阵(二分查找)

Problem: 74. 搜索二维矩阵 文章目录 题目描述思路复杂度Code 题目描述 思路 思路1&#xff1a;映射为一维数组二分查找 1.由于题目矩阵中的元素整体是升序的&#xff0c;我们可以将其放置在一个大小为 m n m \times n mn的一维数组array中进行二分查找 2.对应的映射关系是ar…

蓝桥杯备赛 day1 | 1. 门牌制作, 2. 迷宫, 3. 乘积尾零

最近正好在刷算法题&#xff0c;报了一个蓝桥杯体验一下&#xff0c;但是钱都交了&#xff0c;高低混个奖好吧&#xff0c;今天做的都是一些填空推理题&#xff0c;相当于用程序写下正解&#xff0c;代码是在Dev C上面写的 #include<iostream> #include<bits/stdc.h&g…

HikariCP与Spring Boot的完美集成,让您的应用更高效、更可靠!

随着Spring Boot的流行&#xff0c;越来越多的开发者选择使用它来构建高效、可扩展的应用程序。然而&#xff0c;在构建应用程序的过程中&#xff0c;数据库连接的管理也是一个非常重要的环节。在这篇文章中&#xff0c;我们将介绍如何将HikariCP这一高效的数据库连接池与Sprin…

性能对比:mysql 5.7-8.0-TiDB 7.5-OceanBase 4.2-MariaDB 10.11-机械硬盘-固态硬盘-

1.mysql 5.7-8.0 5.7比8.0优秀 结果&#xff1a;5.7比8.0优秀 10% 2.机械硬盘和固态硬盘 影响不大&#xff0c;主要是CPU 3. JAVA MYSQL 分开 4.『直属 MySQL 』vs 『Docker MySQL』 vs 『Podman MySQL』 直属最好 &#xff0c;其次是Podman&#xff0c;最后是DOCKER 5.MySQL …

Python光速入门 - Flask轻量级框架

FlASK是一个轻量级的WSGI Web应用程序框架&#xff0c;Flask的核心包括Werkzeug工具箱和Jinja2模板引擎&#xff0c;它没有默认使用的数据库或窗体验证工具&#xff0c;这意味着用户可以根据自己的需求选择不同的数据库和验证工具。Flask的设计理念是保持核心简单&#xff0c…