This is the first day of my participation in the August Text Challenge.More challenges in August

On the basis of (3), the function of the sidebar menu is improved, and the basic display of the sidebar menu is completed. There are still some places that can be improved and optimized. This branch routing table has been updated, see the source code.

Main functions: Router-link; Unique submenu processing; Dynamic routing refreshes the blank screen. Menu state saving

Gihub address [Development branch: 4-dev-menu] : github.com/zptime/shan…

Sidebar Menu Router-Link

The menu is displayed before, but the corresponding routing function is not implemented. RouterLink is used to implement route navigation, and the to attribute is used to control the link of the target route.

Official API documentation: router.vuejs.org/zh/api/#rou…

  1. Modify the Layout /sider/menu.vue file
<template>
  <a-menu mode="inline" theme="dark">
    <template v-for="item in menus">
      <! -- Level 1 menu -->
      <a-menu-item v-if=! "" item.children" :key="item.name">
        <! Note: name is used in the to attribute, not path; If path is used, the submenu path in router/index.ts should be defined as/Parent menu route/submenu route, for example, change Role to /system/role. -->
        <router-link :to="{ name: item.name }">
          <span>{{ item.meta && item.meta.title }}</span>
        </router-link>
      </a-menu-item>
       <! -- Submenu -->
      <SubMenu v-else :menu-info="item" :key="item.name" />
    </template>
  </a-menu>
</template>

<script lang="ts>
import { useRouter } from "vue-router";
export default defineComponent({
  setup() {
    // vue-routerObtain the route and view the route methodconst { options.getRoutes } = useRouter();
    console.log("getRoutes", getRoutes());
    console.log("options.routes", options.routes); < /}})script>
Copy the code

UseRouter (), useRouter().getroutes (), useRouter().options.routes, etc

  1. Modify the Layout /sider/ submenu. vue file
<template>
  <! -- No sublevel menu exists -->
  <a-menu-item v-if=! "" item.children" :key="item.name">
    <router-link :to="{ name: item.name }">
      <Icon v-if="item.meta && item.meta.icon" :icon="item.meta.icon" />
      <span>{{ item.meta && item.meta.title }}</span>
    </router-link>
  </a-menu-item>
  <! -- Submenu exists -->
  <SubMenu v-else :menu-info="item" :key="item.name" />
</template>
Copy the code

Sidebar menu subrouting

The previous home page and permission test page have only one sub-menu, in this case, it is not reasonable to show two levels. In this case, it is necessary to display only one level, and the parent menu routes directly value the routes of the child menu.

Check whether the number of submenus && is 1

  1. Modify the Layout /sider/menu.vue file
<template>
  <! -- Level 1 menu -->
  <a-menu-item
    v-if=! "" item.children || (item.children && item.children.length && item.children.length === 1) "
    :key="item.name"
  >
    <router-link
      :to="{ name: item.children && item.children.length && item.children.length === 1 ? item.children[0].name : item.name, }"
    >
      <span>{{ item.meta && item.meta.title }}</span>
    </router-link>
  </a-menu-item>
</template>
Copy the code
  1. Modify the Layout /sider/ submenu. vue file
<template>
  <! -- No sublevel menu exists -->
  <a-menu-item
    v-if=! "" item.children || (item.children && item.children.length && item.children.length === 1)"
    :key="item.name"
  >
    <router-link
      :to="{ name: item.children && item.children.length && item.children.length === 1 ? item.children[0].name : item.name, }"
    >
      <Icon v-if="item.meta && item.meta.icon" :icon="item.meta.icon" />
      <! -- <component v-if="item.meta.icon" :is="item.meta.icon" /> -->
      <span>{{ item.meta && item.meta.title }}</span>
    </router-link>
  </a-menu-item>
</template>
Copy the code

Dynamic route registration refreshes the blank screen

Problem: After you click refresh, the vue-Router reinitializes and the route between the dynamic addRoute and the router does not exist. In this case, a blank page is created.

Solution: Put load menu information in the router’s global guard beforeEach.

Note: to prevent infinite loops, stop according to conditions. I stop condition is store. Getters. Routes. The length > 3, because the default generic routing length is 3, length less than 3, need to load dynamic routing table; If the length is greater than 3, it indicates that it has been added.

  1. Modify the app. vue file
<template>
  <router-view />
</template>

<script lang="ts">
  export default {
    name: "App"};</script>

<style></style>
Copy the code
  1. Example Modify the router/index.ts file
import store from "store/index";

router.beforeEach((to, from, next) = > {
  if(to.path ! = =from.path) {
    document.title = `${to.meta.title}`;
  }

  if (to.path === "/login" || to.path === "/register") {
    next();
  } else if (store.getters.routes.length <= 3) {
    store.dispatch("generateRoutes");
    // @ts-ignorenext({ ... to,replace: true });
  } else{ next(); }});Copy the code

Menu state saving (expand, select)

Each time the page is refreshed, the menu expansion state and the selected state are lost and need to be addressed. I use the combination of localStorage and Vuex

  1. Modify the Layout /sider/menu.vue file
<template>
  <a-menu
    @click="handleMenuClick"
    v-model:openKeys="openKeys"
    v-model:selectedKeys="selectedKeys"
  >
    // ...
  </a-menu>
</template>

<script lang="ts">
  import * as R from "ramda";
  import { defineComponent, toRefs, reactive } from "vue";
  import { useStore } from "store/index";

  export default defineComponent({
    setup() {
      const store = useStore();
      // Save the status through localStorage
      const state = reactive({
        selectedKeys: localStorage.getItem("selectedMenu")? [localStorage.getItem("selectedMenu"] : [],openKeys: localStorage.getItem("openMenu")? R.split(",".localStorage.getItem("openMenu")) : []});const handleMenuClick = (e: Event) = > {
        const { key } = e;
        When clicked, the state is saved to vuex and localStorage
        store.commit("SELECTED_MENU", key);
        store.commit("OPEN_MENU", state.openKeys);
      };

      return{... toRefs(state), handleMenuClick, }; }});</script>
Copy the code
  1. Modify the store/modules/Settings. Ts file
const settings: Module<SettingsState, RootStateTypes> = {
  state() {
    return {
      selectedMenu: [].openMenu: [],}; },getters: {
    selectedMenu: (state) = > state.selectedMenu,
    openMenu: (state) = > state.openMenu,
  },
  mutations: {
    SELECTED_MENU(state, data) {
      localStorage.setItem("selectedMenu", data);
      state.selectedMenu = data;
    },
    OPEN_MENU(state, data) {
      localStorage.setItem("openMenu", data); state.openMenu = data; ,}}};Copy the code

! [Preview effect]