基于vue-router的从后端动态加载菜单的实现
基于vue-router的从后端动态加载菜单的实现
- 源码下载
- 前言
- 后端模拟加载菜单的例子实现
- VueRouterController.java
- CorsConfig.java
- application.yml
- 验证结果
- 前端例子的实现
- 编写axios工具
- 编写API接口
- 编写测试页面
- 1.vue
- 2.vue
- 3.vue
- 改造App.vue实现动态加载路由
- 验证动态路由
源码下载
大家可以直接微信扫描上面的二维码关注我的公众号,然后回复20200113 里面就会给到源代码的下载地址同时会附上相应的视频教程,并定期的与大家分享相关的技术文章。
前言
在前后端分离架构的开发过程中,我们有两种方式来管理的我们的路由,最常见的一种方式就是直接将配置写在前端的代码中,这种方式写起来十分的方便,但是当我们需要做到一些动态菜单的时候就没办法实现了【比如动态的配置相关的报表页面,也许有人会说我们的报表每个都是定制化开发的,那你就用第一种实现方式吧】。,这时候我们就需要用到我们的另外一种的路由实现方式,就是从后端直接读取当前用户的路由信息进行前端的动态加载。
后端模拟加载菜单的例子实现
后端我们直接使用intellij 创建一个spring-boot工程,非常的简单就一个【VueRouterController.java】路由请求的controller、【CorsConfig.java】放开跨域请求的配置以及最后一个application.yml的配置。
VueRouterController.java
package com.vue.router.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author linzf* @since 2020/1/13* 类描述:*/
@RestController
@RequestMapping("menu")
public class VueRouterController {/*** 功能描述: 加载菜单* @return*/@PostMapping("loadMenu")public Map<String,Object> loadTree(){try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}Map<String,Object> result = new HashMap<>(3);result.put("code",200);result.put("msg","菜单加载成功!");List<Map<String,Object>> obj = new ArrayList<>();Map<String,Object> tree = new HashMap<>(3);tree.put("routerPath","views/1.vue");tree.put("name","hello1");tree.put("path","/hello1");obj.add(tree);tree = new HashMap<>(3);tree.put("routerPath","views/2.vue");tree.put("name","hello2");tree.put("path","/hello2");obj.add(tree);tree = new HashMap<>(3);tree.put("routerPath","views/3.vue");tree.put("name","hello3");tree.put("path","/hello3");obj.add(tree);result.put("obj",obj);return result;}}
CorsConfig.java
package com.vue.router.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @author linzf* @since 2019/4/25* 类描述:*/
@Configuration
public class CorsConfig {@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**")// 它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,也可以设置为*号支持全部.allowedHeaders("*")// 该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。.allowedMethods("*")// 本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求.allowedOrigins("*")// 该字段可选,用来指定本次预检请求的有效期,单位为秒.maxAge(1728000);}};}}
application.yml
spring:application:name: router-demoserver:port: 8989
验证结果
我们直接运行当前的项目,然后我们使用我们的postman工具直接访问:http://127.0.0.1:8989/menu/loadMenu我们会看到如下页面则说明我们的后端工程就构建完成了:
前端例子的实现
首先我们需要创建一个基于vue的前端工程,如果不懂的如何创建大家可以直接点击【spring boot +iview 前后端分离架构之前端工程的构建【CMD版】】去创建前端工程,创建过程如下:
创建完成以后我们直接使用我们的开发工具打开我们的前端工程,然后修改我们的package.json文件,修改完成以后代码如下:
{"name": "vue-router-demo-front","version": "1.0.0","description": "A Vue.js project","author": "林泽锋 <282245889@qq.com>","private": true,"scripts": {"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js","start": "npm run dev","build": "node build/build.js"},"dependencies": {"vue": "^2.5.2","vue-router": "^3.0.1","axios": "^0.15.3","axios-mock-adapter": "^1.16.0","mockjs": "^1.0.1-beta3"},"devDependencies": {"autoprefixer": "^7.1.2","babel-core": "^6.22.1","babel-helper-vue-jsx-merge-props": "^2.0.3","babel-loader": "^7.1.1","babel-plugin-syntax-jsx": "^6.18.0","babel-plugin-transform-runtime": "^6.22.0","babel-plugin-transform-vue-jsx": "^3.5.0","babel-preset-env": "^1.3.2","babel-preset-stage-2": "^6.22.0","chalk": "^2.0.1","copy-webpack-plugin": "^4.0.1","css-loader": "^0.28.0","extract-text-webpack-plugin": "^3.0.0","file-loader": "^1.1.4","friendly-errors-webpack-plugin": "^1.6.1","html-webpack-plugin": "^2.30.1","node-notifier": "^5.1.2","optimize-css-assets-webpack-plugin": "^3.2.0","ora": "^1.2.0","portfinder": "^1.0.13","postcss-import": "^11.0.0","postcss-loader": "^2.0.8","postcss-url": "^7.2.1","rimraf": "^2.6.0","semver": "^5.3.0","shelljs": "^0.7.6","uglifyjs-webpack-plugin": "^1.1.1","url-loader": "^0.5.8","vue-loader": "^13.3.0","vue-style-loader": "^3.0.1","vue-template-compiler": "^2.5.2","webpack": "^3.6.0","webpack-bundle-analyzer": "^2.9.0","webpack-dev-server": "^2.9.1","webpack-merge": "^4.1.0"},"engines": {"node": ">= 6.0.0","npm": ">= 3.0.0"},"browserslist": ["> 1%","last 2 versions","not ie <= 8"]
}
然后我们在前端工程的package.json目录执行以下命令:
cnpm install
编写axios工具
与后端建交互我们直接使用的是axios,直接在我们的前端工程的src目录底下创建一个lib目录,同时创建我们的通讯封装js【axios.js】代码如下:
import Axios from 'axios';class httpRequest {constructor() {this.options = {method: '',url: ''};// 存储请求队列this.queue = [];}// 销毁请求实例destroy(url) {delete this.queue[url];const queue = Object.keys(this.queue);return queue.length;}// 请求拦截interceptors(instance, url) {// 添加请求拦截器instance.interceptors.request.use(config => {return config}, error => {// 对请求错误做些什么return Promise.reject(error);});// 添加响应拦截器instance.interceptors.response.use((res) => {let {data} = res;return data;}, (error) => {message.error('服务内部错误');// 对响应错误做点什么return Promise.reject(error);})}// 创建实例create() {let conf = {baseURL: "http://127.0.0.1:8989/",timeout: 5000,headers: {'Access-Control-Allow-Origin': '*','Content-Type': 'application/x-www-form-urlencoded; charset=utf-8','X-URL-PATH': location.pathname}};return Axios.create(conf);}// 请求实例request(options) {let instance = this.create();this.interceptors(instance, options.url);options = Object.assign({}, options);this.queue[options.url] = instance;return instance(options);}
}export default httpRequest;
接着封装【api.request.js】代码如下:
import HttpRequest from './axios';
const axios = new HttpRequest();
export default axios;
最后编写接口调用通用工具【base.js】代码如下:
import axios from './api.request';
import qs from 'qs';
let Axios;if (process.env.NODE_ENV === 'mock') {Axios = require('axios');Axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
}export function fetch(url, params = {}) {if (process.env.NODE_ENV === 'mock') {return new Promise((resolve, reject) => {Axios.post(url, params).then(response => {resolve(response.data);}).catch((error) => {reject(error);})})} else {return new Promise((resolve, reject) => {axiosPost(url,params,resolve)});}
}// 递归调用,保证在token过期刷新token的时候可以实现请求的二次发送
function axiosPost(url,params,resolve){axios.request({url: url,data: qs.stringify(params),method: 'post'}).then(res => {resolve(res);})
}
编写API接口
在src目录底下创建一个api/sys/menu目录,然后创建一个api.menu.js代码如下:
import {fetch} from '../../../lib/base';// 获取菜单数据
export const loadMenu = params => {return fetch('/menu/loadMenu',params);
};
编写测试页面
接着我们需要在src底下创建一个iview文件夹,同时编写三个测试页面,分别是1.vue、2.vue和3.vue,代码如下所示:
1.vue
<template><div><div>这是第一个页面</div><div><button @click="handleClick('hello2')">第二个页面</button><button @click="handleClick('hello3')">第三个页面</button></div></div>
</template>
<script>export default {name: 'hello1',methods:{handleClick(key) {this.$router.push({name: key}).catch(err => {console.log('err=>', err);})}}}
</script>
2.vue
<template><div><div>这是第二个页面</div><div><button @click="handleClick('hello1')">第一个页面</button><button @click="handleClick('hello3')">第三个页面</button></div></div>
</template>
<script>export default {name: 'hello2',methods:{handleClick(key) {this.$router.push({name: key}).catch(err => {console.log('err=>', err);})}}}
</script>
3.vue
<template><div><div>这是第三个页面</div><div><button @click="handleClick('hello1')">第一个页面</button><button @click="handleClick('hello2')">第二个页面</button></div></div></template>
<script>export default {name: 'hello3',methods:{handleClick(key) {this.$router.push({name: key}).catch(err => {console.log('err=>', err);})}}}
</script>
改造App.vue实现动态加载路由
<template><div id="app"><router-view/></div>
</template><script>import {loadMenu} from './api/sys/menu/menu.api';export default {name: 'App',methods: {init() {loadMenu().then(res => {let router = [];for (let i = 0; i < res.obj.length; i++) {let item = res.obj[i];console.log('这是请求返回以后的数据', item.routerPath);item.component = resolve => require([`@/` + item.routerPath], resolve);router.push(item);}this.$router.options.routes.push(...router);this.$router.addRoutes(this.$router.options.routes);console.log("this.$router.options.routes=>", this.$router.options.routes);})},generateRoutesFromMenu (menu = [], routes = []) {}},mounted() {this.init();}}
</script><style>#app {font-family: 'Avenir', Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;}
</style>
验证动态路由
最后我们就需要验证我们的动态路由是否已经OK了,启动我们的后端工程和前端工程,然后我们直接在浏览器中输入以下的地址:http://localhost:8080/#/hello1,我们会看到如下的页面则说明我们的动态路由已经搞定了。
基于vue-router的从后端动态加载菜单的实现相关推荐
- vue高德、谷歌地图动态加载
vue高德.谷歌地图动态加载 前言 引入地图资源 页面使用 完整map.js 前言 因为我们这个项目,做的是国际化项目,考虑的是,在国内使用高德地图,在国外使用谷歌地图,所以在这里做了个动态引入地图, ...
- vue 动态修改后端请求_vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单...
一. 前言 本篇基于 有来商城 youlai-mall微服务项目,通过对vue-element-admin的权限菜单模块理解个性定制其后台接口,实现对vue-element-admin工程几乎不做改动 ...
- osgi框架 android,基于OSGi的Android应用模块动态加载框架设计与实现
摘要: 伴随着移动互联网科技水平向4G的飞跃,移动终端的使用日趋常态化,移动智能设备的普及率越来越高,得到了大量使用者的追捧.与此同时,各手机操作系统下应用商店里正充斥着琳琅满目的移动应用产品,用户对 ...
- react 动态修改路由_升级到 React Router 4 并实现动态加载和模块热替换
这篇文章是升级到Webpack2坑--模块热替换失效页面不自动刷新?的后续.那篇文章主要说明了,升级到 Webpack 2 之后,通过升级webpack-dev-server和react-hot-lo ...
- Vue环境下el-image图片动态加载失败问题
<div v-for="(item,index) in list" :key="index"><el-image :src="ite ...
- J版 OpenStack动态加载菜单图片详解
首先,需要了解OpenStack Horizon动态加载.注册dashboard.PanelGroup.Panel的原理流程 一.这里大致说下与加载左侧菜单相关的几个文件 1. /usr/lib/py ...
- Vue Router系列之路由懒加载
文章の目录 一.具体需要 3 步: 1.安装 `@babel/plugin-syntax-dynamic-import` 包. 2.在 babel.config.js 配置文件中声明该插件. 3.将路 ...
- Vue + Spring Boot 项目实战(十五):动态加载后台菜单
重要链接: 「系列文章目录」 「项目源码(GitHub)」 本篇目录 前言 一.后端实现 1.表设计 2.pojo 3.菜单查询接口(树结构查询) 二.前端实现 1.后台页面设计 2.数据处理 3.添 ...
- 后台管理系统中的antd vue中的问题(动态加载列表a-select-option,后台管理中a-selct-option的回显)
一.antd vue中的a-select的动态加载列表a-select-option 1.既然是动态加载选择框的列表a-select-option,必然存在获取后台数组,并循环 后台数组格式: 数组( ...
最新文章
- Activiti——流程执行历史记录(七)
- puppet 连载二:服务端和客户端安装(ActiveMQ、MCollective)
- 用什么方法才能测量出无线发射模块的功率呢?
- 女子将车垂直开上标志杆,警方回应...
- hdu-5867 Water problem(水题)
- javascript执行机制
- ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp
- dll加载失败,返回126错误
- 数字电路技术可能出现的简答题_数字电子技术基础(Ⅰ)-中国大学mooc-试题题目及答案...
- 东华大学计算机专业在哪个校区,东华大学有几个校区及地址
- 红警安装中出现的问题 win10,黑屏和无法联机对战(缺少ipx协议)的问题。
- 超简单的将python文件改成可以运行的exe方法
- 苹果手机充电口接触不良怎么办_苹果连充电口都要干掉?
- 沉浸其境,共赴云栖数智硬核美学
- 【MATLAB】通信信号调制通用函数 — 傅里叶逆变换
- 微信步数日历打卡小程序
- 求n个整数的平均值与中位数
- 作为一个入门编程小白的感触
- VirtualBox下Ubuntu 20.04全屏显示
- java图片加气泡文字,动态图片加气泡文字 微信动态图片加文字教程