当前位置:   article > 正文

基于element-ui 搭建管理后台_element ui 后台

element ui 后台

本文档从零开始搭建一个通用的管理后台,技术栈为vue2.0 + vue-router + vuex + element-ui + axios 。最终效果如下:

 

左侧为菜单栏,右侧包含头部,面包屑,主内容区。左侧菜单栏可折叠,可全屏,刷新页面后还是之前页面状态。gitee地址:

https://gitee.com/liubangbo/yilin-admain/tree/master

如对您有帮助,麻烦给个star。另外如有问题,欢迎在此留言讨论。

下面对此框架主要部分进行详细阐述。

1. 准备工作

     此框架采用了vue-cli 脚手架创建的项目,选中vuex vue-router,然后按官方文档安装element-ui 并按需加载。最后在安装sass sass-loader的时候如果报错的话,则直接在package.json的devDependencies字段加上"sass": "^1.53.0",  "sass-loader": "^8.0.2",  再npm install 一下就可以了。

2. 模块化业务

   业务按模块划分,在每个模块下写上路由,以及vuex状态。通过接口获取动态路由,对动态路由进行了一个map映射,这样前端就可以自己组织页面结构了。这一块代码在src/register-route-store.js 中:

  1. import { router, store } from "./main";
  2. // import { get } from "./http/index.js"; //real routes fetched from platform
  3. import { get } from "./mockRoutes.js"; //mock routes
  4. export let routesMap = new Map();
  5. const recursionRoutes = (destRoutes, sourceRoutes) => {
  6. if (sourceRoutes.length) {
  7. let temp = null;
  8. sourceRoutes.forEach((item, index) => {
  9. temp = routesMap.get(item.id) ? routesMap.get(item.id) : {};
  10. destRoutes.children &&
  11. destRoutes.children.push(
  12. Object.assign(
  13. {
  14. path: temp.path,
  15. component:
  16. `${item.children}` && `${item.children.length}`
  17. ? (resolve) =>
  18. require([
  19. "@/layouts/components/rightRouteView/index.vue",
  20. ], resolve)
  21. : temp.component,
  22. children:
  23. `${item.children}` && `${item.children.length}` ? [] : null,
  24. },
  25. {
  26. meta: {
  27. label: item.label,
  28. icon: item.icon,
  29. },
  30. }
  31. )
  32. );
  33. if (item.children && item.children.length) {
  34. recursionRoutes(destRoutes.children[index], item.children);
  35. }
  36. });
  37. }
  38. };
  39. const register_dynamicRoutes_store = (dynamicRoutes) => {
  40. console.log("dynamic routes: ", dynamicRoutes);
  41. let routes = [...require("@/layouts/routes/index.js").default];
  42. store.registerModule("layouts", require("@/layouts/store/index.js").default);
  43. dynamicRoutes.length &&
  44. dynamicRoutes.forEach((item, index) => {
  45. require(`@/views${item.path}/routes/index.js`);
  46. routes[0].children.push(
  47. Object.assign(
  48. {
  49. path: item.path,
  50. component: (resolve) =>
  51. require([
  52. `${item.children}` && `${item.children.length}`
  53. ? "@/layouts/components/rightContent/index.vue"
  54. : `@/views${item.path}`,
  55. ], resolve),
  56. children:
  57. `${item.children}` && `${item.children.length}` ? [] : null,
  58. },
  59. {
  60. meta: {
  61. label: item.label,
  62. icon: item.icon,
  63. },
  64. }
  65. )
  66. );
  67. store.registerModule(
  68. item.path.slice(1),
  69. require(`@/views${item.path}/store/index.js`).default
  70. );
  71. if (item.children && item.children.length) {
  72. recursionRoutes(routes[0].children[index], item.children);
  73. }
  74. });
  75. console.log("mapped routes is: ", routes);
  76. router.addRoutes(routes);
  77. store.commit("layouts/setSubRoutesList", routes[0].children);
  78. };
  79. const register_login_route = () => {
  80. const routes = [...require("@/views/login/routes/index.js").default];
  81. router.addRoutes(routes);
  82. };
  83. export const getRoutes = async () => {
  84. try {
  85. const res = await get({
  86. urlKey: "layouts-getNav",
  87. });
  88. if (res.success && res.data && res.data.length) {
  89. //had login, register dynamic routes
  90. register_dynamicRoutes_store(res.data);
  91. router.replace({ path: "/" });
  92. }
  93. } catch (error) {
  94. //no login, register login route
  95. console.error("get nav error, go to login: ", error);
  96. register_login_route();
  97. router.push({
  98. path: "/login",
  99. });
  100. }
  101. };
  102. getRoutes();

3. axios封装

    之前接触的框架,网络接口一般定义在一个文件中,所有业务模块用到的网络接口都写到一个文件中,文件比较长,维护起来也费尽。这里我们把网络接口也进行了业务划分,每个模块写自己用到的网络接口。这部分代码在src/http/index.js文件中:

  1. import axios from "axios";
  2. import { getStorage } from "@/common/js/util.js";
  3. import { TOKEN } from "@/common/js/constant.js";
  4. let pagesUrls = [];
  5. pagesUrls.push({
  6. key: "layouts-getNav",
  7. url: "web/user/getNav",
  8. });
  9. const _pagesUrls = require.context("../views/", true, /urls\/index\.js/);
  10. _pagesUrls.keys().forEach((key) => {
  11. const _moduleName = key.split("/")[1];
  12. const _moduleUrls = require("@/views/" +
  13. _moduleName +
  14. "/urls/index.js").default;
  15. pagesUrls.push(..._moduleUrls);
  16. });
  17. const urlMap = new Map();
  18. pagesUrls.forEach((i) => {
  19. if (i.url) {
  20. urlMap.set(i.key, {
  21. url: "/" + i.url.replace(/^\//, ""), // both sg/cms/homepage and /sg/cms/homepage are OK
  22. });
  23. }
  24. });
  25. let _httpRequest = (obj, _method) => {
  26. if (Object.prototype.toString.call(obj) !== "[object Object]") {
  27. console.error(`the params of http request should be Object`);
  28. return;
  29. }
  30. if (!obj.urlKey || !obj.urlKey.length) {
  31. console.error(`url is empty, you should set it`);
  32. return;
  33. }
  34. const hostKey = obj.hostKey || "HOST";
  35. let _url = urlMap.get(obj.urlKey).url;
  36. if (obj.dynamic) _url = `${_url}${obj.dynamic}`; //dynamic url
  37. delete obj.urlKey;
  38. delete obj.hostKey;
  39. return new Promise((resolve, reject) => {
  40. let _params = {
  41. method: _method,
  42. url: _url,
  43. baseURL: process.env[`VUE_APP_${hostKey.toUpperCase()}`],
  44. };
  45. Object.assign(_params, obj);
  46. axios(_params)
  47. .then((res) => {
  48. resolve(res.data);
  49. })
  50. .catch((err) => {
  51. console.error("axios error: ", err.response);
  52. if (err.response.data.code === 401) {
  53. // loginAgain()
  54. }
  55. reject(err);
  56. });
  57. });
  58. };
  59. axios.interceptors.request.use((config) => {
  60. const token = getStorage(TOKEN);
  61. if (token) {
  62. config.headers["novaAuth"] = token;
  63. } else {
  64. config.headers["Authorization"] = "Basic dGVuYW50OjEyMzQ1Ng==";
  65. }
  66. return config;
  67. });
  68. axios.interceptors.response.use((res) => {
  69. console.log("http res: ", res);
  70. //TODO token过期需要处理
  71. return res;
  72. });
  73. /**
  74. * get方法,对应get请求
  75. * @param {Object} obj
  76. */
  77. export function get(obj) {
  78. return _httpRequest(obj, "GET");
  79. }
  80. /**
  81. * post方法,对应post请求
  82. * @param {Object} obj
  83. */
  84. export function post(obj) {
  85. return _httpRequest(obj, "POST");
  86. }

4. 常量定义

在项目中如果多人协作开发,定义通用常量还是比较重要的,防止出现奇怪bug。例如local-storage的key,我们统一写到常量文件中。这部分代码在src/common/js/constant.js中:

  1. const TOKEN = "iotToken"
  2. const USER_NAME = "userName"
  3. const TABS = "tabs"
  4. const ACTIVE_TAB = "activeTabs"
  5. export {
  6. TOKEN,
  7. USER_NAME,
  8. TABS,
  9. ACTIVE_TAB
  10. }

5. 假路由数据

    在这个通用框架中我们定义了一个假路由数据,如果你们后端返回的动态路由和这个假路由一样,那么这个框架就可以直接拿来用了,直接上手写业务。假路由数据在src/mockRoutes.js中。

  1. const mockRoutes = {
  2. code: 200,
  3. success: true,
  4. data: [
  5. {
  6. id: "8",
  7. icon: "el-icon-setting",
  8. label: "系统管理",
  9. path: "/config",
  10. children: [
  11. {
  12. id: "9",
  13. icon: "el-icon-setting",
  14. label: "页面管理",
  15. path: "/web",
  16. children: [],
  17. },
  18. ],
  19. },
  20. {
  21. id: "100",
  22. icon: "el-icon-user",
  23. label: "测试",
  24. path: "/test",
  25. children: [
  26. {
  27. id: "101",
  28. icon: "el-icon-user",
  29. label: "测试一级菜单",
  30. path: "/test1",
  31. children: [
  32. {
  33. id: "101-0",
  34. icon: "el-icon-user",
  35. label: "一级子页面",
  36. path: "/big",
  37. children: [],
  38. },
  39. ],
  40. },
  41. {
  42. id: "102",
  43. icon: "el-icon-user",
  44. label: "测试一级页面",
  45. path: "/test2",
  46. children: [],
  47. },
  48. {
  49. id: "103",
  50. icon: "el-icon-user",
  51. label: "测试一级菜单",
  52. path: "/test3",
  53. children: [
  54. {
  55. id: "103-0",
  56. icon: "el-icon-user",
  57. label: "测试二级菜单",
  58. path: "/third",
  59. children: [
  60. {
  61. id: "103-0-0",
  62. icon: "el-icon-user",
  63. label: "二级子页面",
  64. path: "/small",
  65. children: [],
  66. },
  67. ],
  68. },
  69. ],
  70. },
  71. ],
  72. },
  73. ],
  74. };
  75. const get = (obj) => {
  76. return new Promise((resolve, reject) => {
  77. setTimeout(() => {
  78. if (obj) {
  79. resolve(mockRoutes);
  80. } else {
  81. reject({});
  82. }
  83. }, 200);
  84. });
  85. };
  86. export { get };

在src/register-route-store.js中的如下代码是进行真假路由数据切换的地方:

  1. // import { get } from "./http/index.js"; //real routes fetched from platform
  2. import { get } from "./mockRoutes.js"; //mock routes

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/111768
推荐阅读
相关标签
  

闽ICP备14008679号