重新新建一个vue3项目

从头搭建一个vue3项目 记录一下自己的遇到的问题以及记录一下自己的学到的东西

栽一棵树最好的时间是现在。

PS:怕作者哪天把文章删了,所以就把自己写的步骤都copy下来了。

参考文章:Vue3+ Vite + Element-Plus + TypeScript 从0到1搭建企业级后台管理系统

新建项目

js 复制代码
//查询node版本 
node -v  // 16.17.0
npm -v //8.15.0

Axios

遇到的问题

解决办法:

在tsconfig.json中加入

js 复制代码
{
  "compilerOptions": {
    // 加入下面这三行代码是为了使import
    "module": "esnext",
    "target": "es5",  // 或其他目标版本
    "outDir": "./dist",
    }
}

路由vue-router

安装vue-router

js 复制代码
npm install vue-router@next

创建路由

新建 src/router/index.ts

js 复制代码
// src/router/index.ts
import { createRouter, createWebHashHistory, RouteRecordRaw ,createWebHistory } from 'vue-router';

export const Layout = () => import('@/layout/index.vue');

// 静态路由
export const constantRoutes: RouteRecordRaw[] = [
  {
    path: '/redirect',
    component: Layout,
    meta: { hidden: true },
    children: [
      {
        path: '/redirect/:path(.*)',
        component: () => import('@/views/redirect/index.vue')
      }
    ]
  },

  {
    path: '/login',
    component: () => import('@/views/login/index.vue'),
    meta: { hidden: true }
  },

  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [
      {
        path: 'dashboard',
        component: () => import('@/views/dashboard/index.vue'),
        name: 'Dashboard',
        meta: { title: 'dashboard', icon: 'homepage', affix: true }
      }
    ]
  }
];

/**
 * 创建路由
 */
const router = createRouter({
  history: createWebHistory(),
  routes: constantRoutes as RouteRecordRaw[],
  // 刷新时,滚动条位置还原
  scrollBehavior: () => ({ left: 0, top: 0 })
});

/**
 * 重置路由
 */
export function resetRouter() {
  router.replace({ path: '/login' });
  location.reload();
}

export default router;

全局注册

js 复制代码
//引入路由
import router from "@/router";
import App from './App.vue'
createApp(App).use(router).mount('#app')

路由守卫

js 复制代码
//路由守卫
import type { RouteRecordRaw } from "vue-router";
import NProgress from "@/utils/nprogress";
import router from "@/router";
import { useUserStoreHook, useUserStore } from "@/store";
// 储存键值对的地方
import { ROLE_ROOT } from "@/constants";

export function setupPermission() {
  const whiteList = ["/login"]; // 无需登录的页面

  router.beforeEach(async (to, from, next) => {
    NProgress.start();
    console.log(to);
    try {
      // 在这里这两个的区别是什么啊 啊啊啊
      console.log("===", useUserStoreHook().isLoggedIn);
      console.log("===", useUserStore().isLoggedIn);
      console.log(whiteList.includes(to.path));

      // 使用 store 暴露的登录态,便于后续扩展(如基于过期时间等)
      const isLoggedIn = useUserStore().isLoggedIn;
      // 未登录处理
      if (!isLoggedIn) {
        if (whiteList.includes(to.path)) {
          next();
        } else {
          next(`/login?redirect=${encodeURIComponent(to.fullPath)}`);
          NProgress.done();
        }
        return;
      }

      // 已登录且访问登录页,重定向到首页
      if (to.path === "/login") {
        next({ path: "/" });
        return;
      }

      // 已登录用户的正常访问
      // const permissionStore = usePermissionStore();
      // const userStore = useUserStore();

      // 路由未生成则生成
      //   if (!permissionStore.isDynamicRoutesGenerated) {
      //     if (!userStore.userInfo?.roles?.length) {
      //       await userStore.getUserInfo();
      //     }

      //     const dynamicRoutes = await permissionStore.generateRoutes();
      //     dynamicRoutes.forEach((route: RouteRecordRaw) => {
      //       router.addRoute(route);
      //     });

      //     next({ ...to, replace: true });
      //     return;
      //   }

      // 检查路由是否存在
      if (to.matched.length === 0) {
        next("/404");
        return;
      }

      // 设置页面标题
      const title = (to.params.title as string) || (to.query.title as string);
      if (title) {
        to.meta.title = title;
      }

      next();
    } catch (error) {
      console.error("❌ Route guard error:", error);
      // 出错时清理状态并重定向到登录页
      //   try {
      //     await useUserStore().resetAllState();
      //   } catch (resetError) {
      //     console.error("❌ Failed to reset user state:", resetError);
      //   }
      next("/login");
      NProgress.done();
    }
  });

  router.afterEach(() => {
    NProgress.done();
  });
}
setupPermission();
/** 判断是否有权限 */
export function hasAuth(
  value: string | string[],
  type: "button" | "role" = "button"
) {
  const { roles, perms } = useUserStore().userInfo;

  // 超级管理员 拥有所有权限
  if (type === "button" && roles.includes(ROLE_ROOT)) {
    return true;
  }

  const auths = type === "button" ? perms : roles;
  return typeof value === "string"
    ? auths.includes(value)
    : value.some((perm) => auths.includes(perm));
}

自定义指令

自定义指令

案例

新建一个directive / highlight /index.ts

js 复制代码
// 自定义指令
import type { Directive } from "vue";
export const highlight: Directive = {
  mounted: (el) =>{
    console.log('elel',el);
    
    return  el.classList.add("is-highlight")
  },
};

新建 directive/ index.ts

js 复制代码
import { App } from "vue";
import { highlight } from "./permission";

// 注册一个全局自定义指令 `v-highlight`
export function setDirectiveFn(app: App<Element>) {
  app.directive("highlight", highlight);
}

main.ts中注册

js 复制代码
import {setDirectiveFn} from "@/directive";
setDirectiveFn(app);
相关推荐
腰间盘突出的红利5 小时前
告别手写CRUD!命令行方式通过swagger实现一键生成页面
前端
有事没事实验室6 小时前
书写腾讯天气遇到的问题
前端·css·html
xulihang6 小时前
如何在网页中嵌入PDF
前端·javascript·html
玖伍贰零壹肆6 小时前
前端偶尔需要—Vue3+Vuetify国际化
前端
玊米粒6 小时前
基础交互 三目运算 if、switch、while 、do while、for、continue、break
javascript
张元清6 小时前
二分查找的艺术:`left <= right` 与 `left < right` 的终极抉择
前端·javascript·算法
蒋星熠6 小时前
Vue 3 + TypeScript 现代前端开发最佳实践(2025版指南)
前端·vue.js·人工智能·pytorch·深度学习·ai·typescript
狂炫一碗大米饭6 小时前
JavaScript 中 Fetch API 的完整指南
前端·api
coding随想6 小时前
还没用过就要被弃用了?深度解析浏览器中的App Cache缓存管理事件
前端