vite+vue3+ts 前端后台项目学习笔记

554 阅读4分钟

vite+vue3+ts 前端后台项目学习笔记

1.vite

npm create vite@latest

1.1vite 路径别名 @ 配置

npm install @types/node --save-dev

Vite配置alias需要两步进行(TS项目)

1、修改vite.config.ts(让程序支持)

2、修改tsconfig.json(让编辑器支持)

vite.config.ts

import { resolve } from "path"

const pathResolve = (dir: string): any => {
  return resolve(__dirname, ".", dir)
}

export default defineConfig({
  ...,
  resolve: {
    alias: {
      "/@": pathResolve("./src/"),
      assets: pathResolve("./src/assets"),
    },
  },
})

tsconfig.json

{
  "compilerOptions": {
	...
    "baseUrl": "./",
    "paths": {
      "/@/*": ["src/*"]
    }
  },
  // "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }],
  "exclude": ["node_modules"]
}

2.router

2.1安装依赖

npm install vue-router

2.2项目引用

2.2.1挂载

import { createApp } from 'vue'
import App from './App.vue'

import router from "./router/index"
createApp(App).use(router).mount('#app')

2.2.2配置路由

在src下创建router/index.ts

import { createRouter, createWebHashHistory } from "vue-router"
import { staticRoutes } from "/@/router/static"

// 创建 router 实例,然后传 `routes` 配置
const router = createRouter({
  history: createWebHashHistory(),
  routes: staticRoutes,
})

// 每次跳转页面前显示进度条
router.beforeEach((to, from, next) => {
  //全局进度条的配置
})

// 路由加载后隐藏进度条
router.afterEach(() => {
  NProgress.done()
})

export default router

在src下创建router/static.ts

import { RouteRecordRaw } from "vue-router"
import Layout from "/@/layouts/index.vue"

/*
 * 静态路由
 */
const staticRoutes: Array<RouteRecordRaw> = [
  {
    // 登录页
    path: "/Login",
    name: "/Login",
    component: () => import("/@/views/login/login.vue"),
    meta: {
      title: "Login",
    },
  },
  {
    path: "/",
    component: Layout,
    children: [
      {
        path: "/dashboard",
        component: () => import("/@/views/dashboard/dashboard.vue"),
        meta: {
          title: "首页",
        },
      },
      {
        path: "/about",
        name: "About",
        component: () => import("/@/views/about.vue"),
      },
    ],
  },
  {
    path: "/:path(.*)*",
    redirect: "/404",
  },
  {
    // 404
    path: "/404",
    name: "notFound",
    component: () => import("/@/views/common/error/404.vue"),
    meta: {
      title: "notFound", // 页面不存在
    },
  },
  {
    // 无权限访问
    path: "/401",
    name: "noPower",
    component: () => import("/@/views/common/error/401.vue"),
    meta: {
      title: "noPower",
    },
  },
]

export { staticRoutes }

2.2.3编程式路由导航 path

app.vue

<template>
  <router-view></router-view>
</template>
<script setup lang="ts"></script>

<style scoped></style>

3.element-plus

3.1安装

npm install element-plus --save

3.2按需导入-自动导入

3.2.1安装插件

首先你需要安装unplugin-vue-componentsunplugin-auto-import这两款插件

npm install -D unplugin-vue-components unplugin-auto-import

3.2.2配置插件

把下列代码插入到你的 Vite配置文件中vite.config.ts

// vite.config.ts
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  // ...
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
})

3.2.3 图标

图标需要另外自己导入

安装:

npm install @element-plus/icons-vue

导入:在main.ts中注册所有图标(官方文档中有自动导入的方法,我试了,查了很多资料都没成功,放弃了)

// main.ts

// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

4.nprogress(进度条)

4.1安装本体

$ npm i nprogress

4.2安装插件

$ npm i @types/nprogress

4.3引入

import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

4.4配置进度条

对进度条进行一些基础配置

//全局进度条的配置
NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 1000, // 递增进度条的速度
  showSpinner: false, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3, // 更改启动时使用的最小百分比
  parent: 'body', //指定进度条的父容器
})

放在router中使用:

// router/index.ts

// 每次跳转页面前显示进度条
router.beforeEach((to, from, next) => {
  //全局进度条的配置
  NProgress.configure({
    easing: "ease", // 动画方式
    speed: 1000, // 递增进度条的速度
    showSpinner: false, // 是否显示加载ico
    trickleSpeed: 200, // 自动递增间隔
    minimum: 0.3, // 更改启动时使用的最小百分比
    parent: "body", //指定进度条的父容器
  })
  NProgress.start()
  next()
})

// 路由加载后隐藏进度条
router.afterEach(() => {
  NProgress.done()
})

4.5在Vue切换路由时展示进度条

现在我们就来使用我们上面封装的Nprogress,这里我们在VueRouter的配置文件中使用,实现切换路由时在顶部展示进度条,首先我们打开VueRouter的配置文件,然后引入我们封装的Nprogress:

// router/index.ts

import { close, start } from '/@/utils/nprogress'

然后我们在创建的Router实例中使用这两个方法:

  • beforeEach:路由切换之前触发;
  • afterEach:路由切换完成后触发
const router = createRouter({
  routes,
  history: createWebHistory(),
})

router.beforeEach((pre, next) => {
  start()
})

router.afterEach(() => {
  close()
})

5.Axios

5.1安装

npm install axios

5.2封装方法

这个封装我重新写了个笔记:Vue 3 + TypeScript 封装 Axios 工具类 - 掘金 (juejin.cn)

我这里就贴个封装好的

在src/utils下封装一个axios.ts的方法

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'

enum ResponseCode {
  Success = 0, // 请求成功
  Unauthorized = 401, // 未授权
  NotFound = 404, // 资源不存在
  InternalServerError = 500, // 服务器内部错误
}

interface ResponseData<T = any> {
  success: boolean;
  code: ResponseCode;
  message: string;
  data?: T;
}

class AxiosService {
  private axiosInstance: AxiosInstance

  constructor() {
    this.axiosInstance = axios.create({
      baseURL: 'https://api.example.com',
      timeout: 5000,
    })

    this.initInterceptor()
  }

  private initInterceptor() {
    // 添加请求拦截器
    this.axiosInstance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        // 在请求发送之前做些什么
        const token = localStorage.getItem('token')
        if (token) {
          // 添加 token 到请求头
          config.headers.Authorization = `Bearer ${token}`
        }
        return config
      },
      (error: any) => {
        // 对请求错误做些什么
        return Promise.reject(error)
      }
    )

    // 添加响应拦截器
    this.axiosInstance.interceptors.response.use(
      (response: AxiosResponse<ResponseData>) => {
        // 对响应数据做些什么
        const { success, code, message, data } = response.data
        if (!success || code !== ResponseCode.Success) {
          // 请求失败或者出现错误
          console.error(`[${code}] ${message}`)
          return Promise.reject(new Error(message))
        }
        return data
      },
      (error: any) => {
        // 对响应错误做些什么
        if (error.response) {
          // 如果服务器返回错误状态码
          switch (error.response.status) {
            case ResponseCode.Unauthorized:
              // 未授权,跳转到登录页
              break
            case ResponseCode.NotFound:
              // 请求的资源不存在
              break
            default:
              // 其他错误
              break
          }
        } else if (error.request) {
          // 如果请求发出去没有收到响应
          console.log(error.request)
        } else {
          // 其他错误
          console.log('Error', error.message)
        }
        return Promise.reject(error)
      }
    )
  }

  public get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return this.axiosInstance.get<T>(url, config)
  }

  public post<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<T> {
    return this.axiosInstance.post<T>(url, data, config)
  }

  public put<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<T> {
    return this.axiosInstance.put<T>(url, data, config)
  }

  public delete<T = any>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<T> {
    return this.axiosInstance.delete<T>(url, config)
  }
}

export const axiosService = new AxiosService()

5.3使用案例

登录api

import axios from "/@/utils/axios"

namespace Login {
  // 用户登录表单
  export interface LoginReqForm {
    username: string
    password: string
  }
  // 登录成功后返回的token
  export interface LoginResData {
    nickName: string
    token: string
  }
}
// 用户登录
export const login = (params: Login.LoginReqForm) => {
  // 返回的数据格式可以和服务端约定
  return axios.post<Login.LoginResData>("/auth/login", params)
}

// 用户登录
export const logout = () => {
  // 返回的数据格式可以和服务端约定
  return axios.get("/auth/logout")
}

6.pinia

6.1安装

$ npm install pinia

6.2引入

import { createPinia } from 'pinia'

app.use(createPinia())

持续更新中。。。。。。