zoukankan      html  css  js  c++  java
  • vue 后台管理系统(1)路由配置

    vue 后台管理系统(1)路由篇

    vue-router 结构一致的配置

    import Vue from 'vue';
    import Router from 'vue-router';
    import Layout from './index.vue';
    
    Vue.use(Router);
    
    /**
     * 这种配置方式有以下弊端
     * 1. product 命名空间重复写多次 代码臃肿
     * 2. 导航的链式关系需要额外的代码逻辑指定(preNav), 比如 商品管理 > 商品列表 > 商品详情 > 商品编辑
     *    您可能会想到路由链式关系可以通过路由段来匹配:/goods/product/:id/edit 一个路由段对应一个路由
     *    => (1) /goods (2) /goods/product (3) /goods/product/:id (4) /goods/product/:id/edit
     *    这样做比较麻烦,而且也没有相关API支持
    
     * 3. 从 $route.matched 获取当前匹配的路径是行不通的,比如访问 /goods/product/1/edit 只匹配到了两个
         (1) /goods
         (2) /goods/product/1/edit
     *  
     */
    export const routes = [
      {
        name: 'M1',
        component: Layout,
        path: '/goods',
        redirect: '/goods/product',
        meta: {
          title: '商品管理'
        },
        children: [
          {
            name: 'M2',
            component: () => import('../Product.vue'),
            path: 'product',
            meta: {
              title: '商品列表',
              activeMenu: 'M2'
            }
          },
          {
            name: 'M3',
            component: () => import('../Product.vue'),
            path: 'product/add',
            meta: {
              title: '增加商品',
              activeMenu: 'M2'
            }
          },
          {
            name: 'M4',
            component: () => import('../Product.vue'),
            path: 'product/:id',
            meta: {
              title: '商品详情',
              activeMenu: 'M2'
            }
          },
          {
            name: 'M5',
            component: () => import('../Product.vue'),
            path: 'product/:id/edit',
            meta: {
              title: '编辑商品',
              activeMenu: 'M2',
              preNav: 'M4'
            }
          }
        ]
      }
    ];
    
    export default new Router({
      routes: routes
    });
    

    自动注入

    页面文件目录按照某种规格编写,读取文件目录生成路由,与 nuxt 类似,约束性太强,而且目录看起来总觉得很奇怪,故不采用。

    自定义结构

    路由结构层次清晰,能满足菜单/导航/权限 等配置。

    import Vue from 'vue';
    import Router from 'vue-router';
    import Layout from './index.vue';
    
    Vue.use(Router);
    
    /**
     * routes 包含了导航链式关系 以及 菜单关系
     */
    export const routes = [
      {
        name: 'M1',
        component: Layout,
        path: '/product',
        redirect: '/product/index',
        meta: {
          title: '商品管理'
        },
        children: [
          {
            name: 'M2',
            component: () => import('../Product.vue'),
            path: 'index',
            meta: {
              title: '商品列表'
            }
          },
          {
            name: 'M3',
            component: () => import('../Brand.vue'),
            path: 'brand',
            meta: {
              title: '品牌管理'
            }
          },
          {
            name: 'M4',
            component: () => import('../Category.vue'),
            path: 'category',
            meta: {
              title: '类目管理'
            }
          }
        ]
      },
      {
        name: 'M5',
        component: Layout,
        path: '/order',
        redirect: '/order/index',
        meta: {
          title: '订单管理'
        },
        children: [
          {
            name: 'M6',
            component: () => import('../OrderList.vue'),
            path: 'index',
            meta: {
              title: '订单列表'
            },
            children: [
              {
                name: 'M7',
                component: () => import('../OrderDetail.vue'),
                path: 'add',
                hidden: true,
                meta: {
                  title: '创建订单'
                }
              },
              {
                name: 'M8',
                component: () => import('../OrderDetail.vue'),
                path: ':orderId',
                hidden: true,
                meta: {
                  title: '订单详情'
                },
                children: [
                  {
                    name: 'M9',
                    component: () => import('../OrderDetail.vue'),
                    path: 'edit',
                    meta: {
                      title: '编辑订单'
                    }
                  }
                ]
              }
            ]
          }
        ]
      }
    ];
    
    /**
     * 生成 vue-router routes
     */
    const makeRoutes = () => {
      const rList = [];
    
      const rawChildren = (parent, children = [], top) => {
        children.forEach(item => {
          item.path = (parent.path + '/' + item.path).replace('//', '/');
          const child = {
            ...item
          };
          delete child.children;
          top.children.push(child);
          rawChildren(item, item.children, top);
        });
      };
    
      routes.forEach(item => {
        const child = {
          ...item,
          children: []
        };
        rawChildren(child, item.children || [], child);
        rList.push(child);
      });
    
      return rList;
    };
    
    export default new Router({
      routes: makeRoutes()
    });
    

    左侧菜单配置:

    <template>
      <el-menu
        class="menu"
        :default-active="activeMenu"
        background-color="#282c43"
        text-color="#fff"
        active-text-color="#fc652f"
      >
        <MenuItem v-for="item in routes" :menu="item" :key="item.name" :routes="routes" />
      </el-menu>
    </template>
    
    <script>
    // sidebar.vue
    import { routes } from '../router';
    import MenuItem from './menu-item';
    
    export default {
      components: {
        MenuItem
      },
      data() {
        return {
          routes,
          isCollapse: true
        };
      },
      computed: {
        activeMenu() {
          const meta = this.$route.meta;
          return meta && meta.menuValue ? meta.menuValue : this.$route.name;
        }
      }
    };
    </script>
    
    <style scoped>
    .menu {
      border-right: 0;
    }
    .menu-item {
      padding: 0 12px;
      line-height: 40px;
    }
    </style>
    
    <template>
      <div v-if="menu.meta && !menu.hidden">
        <template v-if="!hasChildren(menu)" >
          <el-menu-item>
            <template slot="title">
              <span slot="title">{{ menu.meta.title }}</span>
            </template>
          </el-menu-item>
        </template>
    
        <template v-else>
          <el-submenu :index="getMenuIndex(menu)">
            <template slot="title">
              <i class="el-icon-user-solid" v-if="showIcon"></i>
              <span slot="title">{{ menu.meta.title }}</span>
            </template>
            <child-menu
              v-for="child in menu.children"
              :key="child.name"
              :menu="child"
              :show-icon="false"
            />
          </el-submenu>
        </template>
      </div>
    </template>
    
    <script>
    // menu-item.vue
    import router from '../router';
    
    export default {
      name: 'child-menu',
      props: {
        menu: {
          type: Object,
          default: null
        },
        'show-icon': {
          type: Boolean,
          default: true
        }
      },
    
      created() {
        this.$watch('menu', v => {
          console.log(v);
        });
      },
    
      methods: {
        getMenuIndex($route) {
          return $route.name;
        },
    
        hasChildren(menu) {
          if (!menu.children) return false;
          return !!menu.children.filter(menu => !menu.hidden).length;
        },
    
        gotoPath(route) {
          if (route.name !== this.$route.name) {
            this.$router.push({ name: route.name });
          }
        },
    
        hasPermission(route) {
          return true;
        }
      }
    };
    </script>
    
    <style scoped>
    .menu {
      border-right: 0;
    }
    
    .menu-item {
      padding: 0 12px;
      line-height: 40px;
    }
    </style>
    

    导航面包屑:

    <template>
      <div>
        <span v-for="bread in breadList" :key="bread.name">
          {{ bread.meta.title }}
        </span>
      </div>
    </template>
    
    <script>
    import { routes } from './router';
    
    export default {
      data() {
        return {
          routes,
          breadList: []
        };
      },
      created() {
        let res = null;
        const find = (list, path) => {
          list.forEach(item => {
            const curPath = [...path].concat(item);
            if (item.name === this.$route.name) {
              res = curPath;
            }
            item.children && find(item.children, curPath);
          });
        };
    
        find(routes, []);
        this.breadList = res;
      }
    };
    </script>
    
  • 相关阅读:
    莫队专题
    AJAX XML 实例
    AJAX 简介
    AJAX 服务器响应
    AJAX 创建XMLHttpRequest 对象
    AJAX 教程
    AJAX 向服务器发送请求
    AJAX onreadystatechange 事件
    AJAX ASP/PHP 请求实例
    让卖场的死角“起死回生”
  • 原文地址:https://www.cnblogs.com/GManba/p/13736971.html
Copyright © 2011-2022 走看看