Vue3.0 Vite + windicss + ...实战项目(十五.二)

十九.如何动态添加后端返回的菜单实现动态路由的添加呢?

1. router/index.js 文件
import { createRouter, createWebHashHistory } from "vue-router";

import Admin from "~/Layout/admin.vue";
import Index from "~/pages/index.vue";
import Login from "~/pages/Login/login.vue";
import NotFound from "~/pages/NotFound/404.vue";
import GoodList from "~/pages/Goods/List.vue";
import CategoryList from "~/pages/Category/ListCategory.vue";
// const routes = [
//   {
//     path: "/",
//     component: Admin,
//     children: [
//       {
//         path: '/',
//         component: Index,
//         meta: {
//           title: "后台首页"
//         }
//       },

//       {
//         path: '/goods/list',
//         component: GoodList,
//         meta: {
//           title: "商品管理"
//         }
//       },
//       {
//         path: '/category/list',
//         component: CategoryList,
//         meta: {
//           title: "分类管理"
//         }
//       }
//     ]
//   },

//   {
//     path: "/login",
//     component: Login,
//     meta: {
//       title: "登录"
//     }
//   },
//   {
//     path: "/:pathMatch(.*)*",
//     name: "NotFound",
//     component: NotFound,
//     meta: {
//       title: "404-NotFound"
//     }
//   },
// ];

// 这个是公共路由 所有用户共享
const routes = [
  {
    path: "/",
    name: "admin",
    component: Admin,
  },

  {
    path: "/login",
    name: "login",
    component: Login,
    meta: {
      title: "登录",
    },
  },
  {
    path: "/:pathMatch(.*)*",
    name: "NotFound",
    component: NotFound,
    meta: {
      title: "404-NotFound",
    },
  },
];
// 1. 动态路由,用于匹配菜单动态添加路由
const aysncRoutes = [
  {
    path: "/",
    component: Index,
    name: "/",
    meta: {
      title: "后台首页",
    },
  },

  {
    path: "/goods/list",
    component: GoodList,
    name: "/goods/list",
    meta: {
      title: "商品管理",
    },
  },
  {
    path: "/category/list",
    component: CategoryList,
    name: "/category/list",
    meta: {
      title: "分类管理",
    },
  },
];

export const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

//  2. 动态添加路由的方法
export const addRoutes = (menus) => {
  console.log(menus);
  // 是否有新的路由
  let hasNewRoutes = false;
  const findAndAddRoutesByMenus = (arr) => {
    arr.forEach((e) => {
      let item = aysncRoutes.find((o) => o.path == e.frontpath);
      // item: 是否有item; router.hasRoute():检查路由是否存在
      // router.hasRoute(): 传递一个name,所以要在路由中写上name名称
      if (item && !router.hasRoute(item.path)) { // !router.hasRoute(item.path): 没有注册过路由
        // addRoute():参数一: 父级路由的name值,参数二:满足条件的对象 
        router.addRoute("admin", item);
        hasNewRoutes = true;
      }
      // e: 是一个对象 
      if (e.child && e.child.length > 0) {
        findAndAddRoutesByMenus(e.child);
      }
    });
  };

  findAndAddRoutesByMenus(menus);

  return hasNewRoutes;
  // console.log(router.getRoutes());
};

2. 
// 专门处理权限相关的代码

// 1. 引入路由实例
import { router, addRoutes } from "~/router";
import { getToken } from "~/commonCookie/Auth";
import { Toast, showFullLoading, hideFullLoading } from "~/commonCookie/utils";
import store from "./store";

// 前置路由守卫
router.beforeEach(async (to, from, next) => {
  // 只要路由发生了变化 要实现loading效果
  showFullLoading();

  const token = getToken();
  if (!token && to.path !== "/login") {
    Toast("请先登录", "error");
    return next({ path: "/login" });
  }
  // 防止重复登录
  if (token && to.path == "/login") {
    Toast("请务重复登录", "error");
    return next({ path: from.path ? from.path : "/" });
  }

  let hasNewRoutes = false;
  // 如果用户登录了 ,自动获取用户信息, 并储存在vuex中,
  // 这种是为了防止 第一次可以获取到数据, 但是在页面刷新以后数据会丢失
  if (token) {
    const res = await store.dispatch("getInfo");
    // console.log(res);

    // 动态添加路由 hasNewRoutes:返回值是Boolean当有新的路由的时候 值为true
    hasNewRoutes = addRoutes(res.menus);
  }

  // 设置页面标题
  // console.log(to.meta.title); // 显示的是当前路由的title
  let title = to.meta?.title + "--振楚后台系统";
  document.title = title;
  console.log(to);
  // 防止路由刷新页面消失,hasNewRoutes:返回值是Boolean当有新的路由的时候 值为true
  hasNewRoutes ? next(to.fullPath) : next();
});

// 全局后置守卫
router.afterEach((to, from) => {
  // 当路由加载完成以后 关闭全局的进度条
  hideFullLoading();
});

二十. 封装一个完整版的标签导航

1. FTagListHooks.js
import { ref } from "vue";
import { useRoute, onBeforeRouteUpdate, useRouter } from "vue-router";
import { useCookies } from "@vueuse/integrations/useCookies";
export const useTabList = () => {
  const route = useRoute();
  const router = useRouter();
  const cookie = useCookies();
  const activeTab = ref(route.path);
  const tabList = ref([
    {
      title: "后台首页",
      path: "/",
    },
  ]);
  const changeTab = (t) => {
    console.log(t);
    activeTab.value = t;
    router.push(t);
  };
  const removeTab = (t) => {
    console.log(t); // 拿到path值
    let tabs = tabList.value;
    let a = activeTab.value;
    if (a == t) {
      tabs.forEach((tab, index) => {
        if (tab.path == t) {
          const nextTab = tabs[index + 1] || tabs[index - 1];
          if (nextTab) {
            a = nextTab.path; // 点击删除,匹配到当前上一个或者写一个的路径
          }
        }
      });
    }

    activeTab.value = a;

    tabList.value = tabList.value.filter((tab) => tab.path != t);

    cookie.set("tabList", tabList.value);
  };
  // 监听当前路由改变
  onBeforeRouteUpdate((to, from) => {
    // console.log(to);
    // console.log(from);
    activeTab.value = to.path;
    addTab({
      title: to.meta.title,
      path: to.path,
    });
  });

  const addTab = (tabObj) => {
    let noTab = tabList.value.findIndex((t) => t.path == tabObj.path) == -1; // 代表此时循环是数据是没有这个tab
    if (noTab) {
      tabList.value.push(tabObj);
    }
    cookie.set("tabList", tabList.value);
  };

  // 初始化标签导航列表,当你在刷新浏览器的时候 添加的tab标签没有了
  const initTabList = () => {
    let tabs = cookie.get("tabList");
    if (tabs) {
      tabList.value = tabs;
    }
  };

  initTabList();

  // 关闭标签
  const handleClode = (c) => {
    // closeOther
    // closeAll
    if (c == "closeAll") {
      // 切换到首页
      activeTab.value = "/";
      // 过滤只剩下首页
      tabList.value = [
        {
          title: "后台首页",
          path: "/",
        },
      ];
    } else if (c == "closeOther") {
      tabList.value = tabList.value.filter(
        (tab) => tab.path == "/" || tab.path == activeTab.value
      );
    }

    cookie.set("tabList", tabList.value);
  };

  return {
    activeTab,
    tabList,
    changeTab,
    removeTab,
    handleClode
  }
};

2. FTagList.vue





实际截图

image.png

二十一. 利用keep-alive 实现 全局 页面缓存

image.png

二十二.设置全局过渡动画

image.png

二十三.使用 animate.style 库来做动画效果

使用 animate.style 库来做动画效果

image.png

二十四.如何实现数字滚动 动画效果

gsap库的地址

1. 要是用一个第三方的gsap库安装命令: npm i gsap

2. 封装一个数字滚动组件 CountTo.vue组件






3. 在页面使用
// 3.1 引入
import CountTo from "~/components/CountTo/CountTo.vue"

// 3.2 标签上使用
 
image.png

二十五.对Echarts图标封装

1. 安装Eacharts:  cnpm install echarts --save

2. 封装一个Eacharts.vue文件






3. 在需要引用的页面中使用
import CheckEChart from "~/components/Compone/ComponentIndexEacharts.vue";

    
        
      
      
 

实际截图:

image.png

你可能感兴趣的:(Vue3.0 Vite + windicss + ...实战项目(十五.二))