likes
comments
collection
share

布局: 先来实现左侧栏吧!

作者站长头像
站长
· 阅读数 14

布局: 先来实现左侧栏吧!

前言

前一段时间, 写了强盛集团管理系统(基于BPMN引擎的工作流系统), 打算使用qiankun改造下项目架构, 迈向微前端。在第一章的基础上, 搭建基座应用的布局, 先后搭建左侧栏、顶部栏、内容栏、底部栏。

搭建左侧栏

安装 Element UI

  1. 基座下安装 element ui
    yarn add element-ui@2.4.5 -s

因为老项目安装的是 vue2.x, 所以 element ui 不需要安装最新的版本

  1. 创建插件文件目录

因为后期可能会有很多的插件依赖需要安装, 所以抽离出plugins 文件来放置插件, 同时也方便后期基座提取公共依赖。

新建plugins/element.js

新建plugins/index.js

  1. plugins/element.js中引入element ui
import Vue from "vue";
import Element from "element-ui";
import "element-ui/lib/theme-chalk/index.css";

// Vue.use(Element)
Vue.use(Element, {
  size: "mini", // set element-ui default size
  // locale: enLang // 如果使用中文,无需设置,请删除
});
  1. 新建插件主入口plugins/index.js
import "./element";

布局

布局: 先来实现左侧栏吧!

├─components
│  └─Layout
│      ├─index.vue
│      └─components
│         ├─LayoutAside.vue
│         ├─LayoutAsideMenuItem.vue
│         ├─LayoutHeader.vue
│         ├─LayoutMain.vue
│         ├─LayoutFooter.vue
│         └─index.js

将布局单独抽离, 新建layout/index.js文件, 可以直接放在src目录下,或components目录下。这里选择components目录下。

  1. 新建Layout/components/LayoutAside.vue 左侧栏
<!-- 左侧栏 -->
<template>
  <div class="layout-aside">
    <div class="layout-aside-logo">
      <img class="logo" src="@/assets/logo.png" alt="" />
      <span class="name" v-if="!isCollapse">强盛集团</span>
    </div>
    <el-scrollbar class="layout-aside-scrollbar">
      <el-menu
        :class="['layout-aside-menu']"
        :default-active="defaultActive"
        router
        unique-opened
        :collapse="isCollapse"
        background-color="#2c3e50"
        text-color="#ecf0f1"
        active-text-color="#1890ff"
      >
        <layout-aside-menu-item
          v-for="item in menuRoutes"
          :item="item"
          :key="item.path"
        />
      </el-menu>
    </el-scrollbar>
  </div>
</template>

<script>
import LayoutAsideMenuItem from "./LayoutAsideMenuItem.vue";
import { routes } from "@/router/index";
import { mapGetters } from "vuex";
export default {
  name: "LayoutAside",
  components: { LayoutAsideMenuItem },
  computed: {
    defaultActive() {
      return "/system/"; // 默认打开的页面
    },
  },
  data() {
    return {
      menuRoutes: routes,
    };
  },
};
</script>
<style lang="less" scoped>
.layout-aside {
  height: 100vh;
  user-select: none;
  background-color: #2c3e50;
  .layout-aside-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 60px;
    line-height: 60px;
    padding: 0 20px;
    color: #fff;
    font-size: 25px;
    font-weight: 700;
    .logo {
      width: 30px;
      height: 26px;
      margin-right: 3px;
    }
    .name {
      line-height: 26px;
      color: rgba(0, 113, 188, 1);
    }
    .layout-aside-scrollbar {
      height: calc(100vh - 60px);
      overflow-x: hidden;
      padding-left: 5px;
      .layout-aside-menu {
        border-right: none;
        &:not(.el-menu--collapse) {
          width: 220px;
        }
      }
    }
  }
}
.el-scrollbar__wrap {
  overflow-x: hidden !important;
}
</style>
  1. 新建Layout/components/LayoutAsideMenuItem.vue 左侧栏
<!-- 左侧栏 - Item -->
<template>
  <li class="layout-aside-menu-item">
    <el-submenu v-if="item.children" :index="item.path">
      <template slot="title">
        <span slot="title">{{ item.meta && item.meta.title }}</span>
      </template>
      <layout-aside-menu-item
        v-for="subItem in item.children"
        :item="subItem"
        :key="subItem.path"
      >
      </layout-aside-menu-item>
    </el-submenu>
    <el-menu-item v-else :route="item.path" :index="item.path">
      <span slot="title">{{ item.meta && item.meta.title }}</span>
    </el-menu-item>
  </li>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  name: "LayoutAsideMenuItem",
  props: ["item"],
  data() {
    return {};
  },
  methods: {},
  created() {},
  mounted() {},
};
</script>
<style lang="scss" scoped></style>

暂时先不管 icon, 后面逐步完善。

  1. 新建Layout/components/LayoutHeader.vue 头部栏
<!-- 头部栏 -->
<template>
  <div class="">
    <nav>
      <router-link to="/">基座首页</router-link> |
      <router-link to="/about">基座关于页</router-link> |
      <router-link to="/vue/">微应用首页</router-link> |
      <router-link to="/vue/about">微应用关于页</router-link>
    </nav>
  </div>
</template>

<script>
export default {
  name: "",
  data() {
    return {};
  },
  methods: {},
  created() {},
  mounted() {},
};
</script>
<style lang="less" scoped>
nav {
  padding: 30px;

  a {
    font-weight: bold;
    color: #2c3e50;

    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

头部区域暂时先防置之前的 nav

  1. 新建Layout/components/LayoutMain.vue 内容区
<!-- 内容区 -->
<template>
  <div class="">
    内容区
    <router-view></router-view>
    <div id="Appmicro"></div>
  </div>
</template>

<script>
export default {
  name: "",
  data() {
    return {};
  },
  methods: {},
  created() {},
  mounted() {},
};
</script>
<style lang="less" scoped></style>

内容区防置了router-view标签 和 idAppmicro的元素, 而这个元素将用来注入微应用

  1. 新建Layout/components/LayoutFooter.vue 底部栏
<!-- 底部栏 -->
<template>
  <div class="">底部栏</div>
</template>

<script>
export default {
  name: "",
  data() {
    return {};
  },
  methods: {},
  created() {},
  mounted() {},
};
</script>
<style lang="less" scoped></style>
  1. 新建Layout/components/index.js, 用来作为 layout 组件的入口文件
export { default as LayoutAside } from "./LayoutAside";
export { default as LayoutHeader } from "./LayoutHeader";
export { default as LayoutMain } from "./LayoutMain";
export { default as LayoutFooter } from "./LayoutFooter";
  1. 新建Layout/index.vue, Layout 布局的统一入口
<!-- 布局 -->
<template>
  <section class="layout">
    <layout-aside></layout-aside>
    <section class="layout-container">
      <layout-header></layout-header>
      <layout-main></layout-main>
      <layout-footer></layout-footer>
    </section>
  </section>
</template>

<script>
import {
  LayoutAside,
  LayoutHeader,
  LayoutMain,
  LayoutFooter,
} from "./components";

export default {
  name: "Layout",
  components: { LayoutAside, LayoutHeader, LayoutMain, LayoutFooter },
  data() {
    return {};
  },
  methods: {},
  created() {},
  mounted() {},
};
</script>
<style lang="less" scoped>
.layout {
  width: 100vw;
  height: 100vh;
  display: flex;
  .layout-container {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: auto;
  }
}
</style>

改造App.vue

<template>
  <div id="app">
    <router-view />
  </div>
</template>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
</style>

将 nav 移到了头部栏中, 此时就可以去掉 nav 部分的 html 和 css

此时你会发现除了基座的部分内容可见, 其余的路径都会报错, 接下来去改造下路由

改造 router

  1. 布局layout不可见是因为没有用到, 所以只需要在 router 中, 给 routes 添加一层布局
import Vue from "vue";
import Layout from "@/components/Layout";
import VueRouter from "vue-router";
import HomeView from "../views/HomeView.vue";

Vue.use(VueRouter);

export const routes = [
  {
    path: "/",
    name: "home",
    component: Layout,
    redirect: "/",
    meta: { title: "基座" },
    children: [
      {
        path: "/",
        name: "home",
        meta: { title: "基座首页" },
        component: HomeView,
      },
      {
        path: "/about",
        name: "about",
        meta: { title: "基座关于" },
        component: () =>
          import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
      },
    ],
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

export default router;

布局: 先来实现左侧栏吧!

此时基座的两个页面已经可以正常访问, 但点击头部栏的微应用页面导航则报错

那我们先来将微应用的路由添加进去吧

  1. 新建router/modules/system, 创建系统路由
// 系统菜单
import Layout from "@/components/Layout";
const appRouter = {
  path: "/system",
  component: Layout,
  name: "System",
  meta: {
    title: "微应用",
    icon: "table",
  },
  children: [
    {
      path: "/system/",
      name: "Home",
      meta: { title: "微应用首页", icon: "menuSon" },
    },
    {
      path: "/system/about",
      name: "About",
      meta: { title: "微应用关于", icon: "menuSon" },
    },
  ],
};
export default appRouter;
  1. 将系统路由注册到路由表router/index.js
// 1. 引入
import SystemRoute from "./modules/system";

export const routes = [{}, ...SystemRoute];

布局: 先来实现左侧栏吧!

此时点击微应用路径还是报错状态, 还需要修改register-apps.js的微应用配置

  1. 修改register-apps.js
registerMicroApps(
  [
    {
      name: "system",
      entry: "//localhost:1100", // 默认vue启动的入口是1100端口
      activeRule: "/system", // 当路径是 /vue的时候启动
      container: "#Appmicro", // 应用挂载的位置
      loader,
      props: {},
    },
  ],
  {
    beforeLoad() {
      console.log("before load");
    },
    beforeMount() {
      console.log("before mount");
    },
    afterMount() {
      console.log("after mount");
    },
    beforeUnmount() {
      console.log("before unmount");
    },
    afterUnmount() {
      console.log("after unmount");
    },
  }
);

修改了container 挂载节点, 和nameactiveRule、字段,由vue改为了system, 为了方便后序改造系统配置模块

  1. 微应用中router/index.js, 需要把基路径也改一下
const router = new VueRouter({
  mode: 'history',
  base: window.__POWERED_BY_QIANKUN__ ? "/system/" : "/",
  routes
})

布局: 先来实现左侧栏吧!

总结

至此, 布局之左侧栏完成, 然后比较简单, 正好可以从入门开始, 完整获得微前端的入门级体验。

实际很多项目也是从0开始,优先开发业务功能,逐步完成代码规范、提交规范。

而本专栏就是打算将Vue2.x的老项目完成技术架构升级,从而达到技术栈更新、迁移、重构、重写等架构演进。

项目地址: gitee.com/wang_xi_lon…