Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(2)

简介: Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(2)

Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(1):

https://developer.aliyun.com/article/1395742


style 标签使用SCSS全局变量

<!-- src/components/HelloWorld.vue -->
<template>
  <div class="box" />
</template>
<style lang="scss" scoped>
.box {
  width: 100px;
  height: 100px;
  background-color: $bg-color;
}
</style>

上面导入的 SCSS 全局变量在 TypeScript 不生效的,需要创建一个以 .module.scss 结尾的文件

// src/styles/variables.module.scss
// 导出 variables.scss 文件的变量
:export{
    bgColor:$bg-color
}

TypeScript 使用 SCSS 全局变量

<!-- src/components/HelloWorld.vue -->
<script setup lang="ts">
  import variables from "@/styles/variables.module.scss";
  console.log(variables.bgColor)  
</script>
<template>
  <div style="width:100px;height:100px" :style="{ 'background-color': variables.bgColor }" />
</template>

整合 UnoCSS


UnoCSS 是一个具有高性能且极具灵活性的即时原子化 CSS 引擎 。


参考:Vite 安装 UnoCSS 官方文档


安装依赖

npm install -D unocss

vite.config.ts 配置

// vite.config.ts
import UnoCSS from 'unocss/vite'
export default {
  plugins: [
    UnoCSS({ /* options */ }),
  ],
}

main.ts 引入 uno.css

// src/main.ts
import 'uno.css'

VSCode 安装 UnoCSS 插件

16.png

再看下具体使用方式和实际效果:

17.png

如果UnoCSS 插件智能提示不生效,请参考:VSCode插件UnoCSS智能提示不生效解决


整合 Pinia


Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。


参考:Pinia 官方文档


安装依赖

npm install pinia

main.ts 引入 pinia

// src/main.ts
import { createPinia } from "pinia";
import App from "./App.vue";
createApp(App).use(createPinia()).mount("#app");

定义 Store


根据 Pinia 官方文档-核心概念 描述 ,Store 定义分为选项式组合式 , 先比较下两种写法的区别:


选项式 Option Store

18.png

组合式 Setup Store

19.png

至于如何选择,官方给出的建议 :选择你觉得最舒服的那一个就好 。


这里选择组合式,新建文件 src/store/counter.ts

// src/store/counter.ts
import { defineStore } from "pinia";
export const useCounterStore = defineStore("counter", () => {
  // ref变量 → state 属性
  const count = ref(0);
  // computed计算属性 → getters
  const double = computed(() => {
    return count.value * 2;
  });
  // function函数 → actions
  function increment() {
    count.value++;
  }
  return { count, double, increment };
});

父组件

<!-- src/App.vue -->
<script setup lang="ts">
import HelloWorld from "@/components/HelloWorld.vue";
import { useCounterStore } from "@/store/counter";
const counterStore = useCounterStore();
</script>
<template>
  <h1 class="text-3xl">vue3-element-admin-父组件</h1>
  <el-button type="primary" @click="counterStore.increment">count++</el-button>
  <HelloWorld />
</template>

子组件

<!-- src/components/HelloWorld.vue -->
<script setup lang="ts">
import { useCounterStore } from "@/store/counter";
const counterStore = useCounterStore();
</script>
<template>
  <el-card  class="text-left text-white border-white border-1 border-solid mt-10 bg-[#242424]" >
    <template #header> 子组件 HelloWorld.vue</template>
    <el-form>
      <el-form-item label="数字:"> {{ counterStore.count }}</el-form-item>
      <el-form-item label="加倍:"> {{ counterStore.double }}</el-form-item>
    </el-form>
  </el-card>
</template>

效果预览

1.gif

环境变量


Vite 环境变量主要是为了区分开发、测试、生产等环境的变量


参考: Vite 环境变量配置官方文档


env配置文件


项目根目录新建 .env.development 、.env.production


开发环境变量配置:.env.development

# 变量必须以 VITE_ 为前缀才能暴露给外部读取
VITE_APP_TITLE = 'vue3-element-admin'
VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/dev-api'

生产环境变量配置:.env.production

VITE_APP_TITLE = 'vue3-element-admin'
VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/prod-api'

境变量智能提示


新建 src/types/env.d.ts文件存放环境变量TS类型声明

// src/types/env.d.ts
interface ImportMetaEnv {
  /**
   * 应用标题
   */
  VITE_APP_TITLE: string;
  /**
   * 应用端口
   */
  VITE_APP_PORT: number;
  /**
   * API基础路径(反向代理)
   */
  VITE_APP_BASE_API: string;
}
interface ImportMeta {
  readonly env: ImportMetaEnv;
}

使用自定义环境变量就会有智能提示,环境变量的读取和使用请看下一节的跨域处理中的 vite.config.ts的配置

20.png

跨域处理


跨域原理


浏览器同源策略: 协议、域名和端口都相同是同源,浏览器会限制非同源请求读取响应结果。


本地开发环境通过 Vite 配置反向代理解决浏览器跨域问题,生产环境则是通过 nginx 配置反向代理 。


vite.config.ts 配置代理

21.png

表面肉眼看到的请求地址: http://localhost:3000/dev-api/api/v1/users/me


真实访问的代理目标地址: http://vapi.youlai.tech/api/v1/users/me

1.png

整合 Axios


Axios 基于promise可以用于浏览器和node.js的网络请求库


参考: Axios 官方文档


安装依赖

npm install axios

Axios 工具类封装

//  src/utils/request.ts
import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import { useUserStoreHook } from '@/store/modules/user';
// 创建 axios 实例
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 50000,
  headers: { 'Content-Type': 'application/json;charset=utf-8' }
});
// 请求拦截器
service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    const userStore = useUserStoreHook();
    if (userStore.token) {
      config.headers.Authorization = userStore.token;
    }
    return config;
  },
  (error: any) => {
    return Promise.reject(error);
  }
);
// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    const { code, msg } = response.data;
    // 登录成功
    if (code === '00000') {
      return response.data;
    }
    ElMessage.error(msg || '系统出错');
    return Promise.reject(new Error(msg || 'Error'));
  },
  (error: any) => {
    if (error.response.data) {
      const { code, msg } = error.response.data;
      // token 过期,跳转登录页
      if (code === 'A0230') {
        ElMessageBox.confirm('当前页面已失效,请重新登录', '提示', {
          confirmButtonText: '确定',
          type: 'warning'
        }).then(() => {
          localStorage.clear(); // @vueuse/core 自动导入
          window.location.href = '/';
        });
      }else{
          ElMessage.error(msg || '系统出错');
      }
    }
    return Promise.reject(error.message);
  }
);
// 导出 axios 实例
export default service;

录接口实战


访问 vue3-element-admin 在线接口文档, 查看登录接口请求参数和响应数据类型

2.png

点击 生成代码 获取登录响应数据 TypeScript 类型定义

3.png

将类型定义复制到 src/api/auth/types.ts 文件中

/**
 * 登录请求参数
 */
export interface LoginData {
  /**
   * 用户名
   */
  username: string;
  /**
   * 密码
   */
  password: string;
}
/**
 * 登录响应
 */
export interface LoginResult {
  /**
   * 访问token
   */
  accessToken?: string;
  /**
   * 过期时间(单位:毫秒)
   */
  expires?: number;
  /**
   * 刷新token
   */
  refreshToken?: string;
  /**
   * token 类型
   */
  tokenType?: string;
}

登录 API 定义

// src/api/auth/index.ts
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { LoginData, LoginResult } from './types';
/**
 * 登录API 
 * 
 * @param data {LoginData}
 * @returns
 */
export function loginApi(data: LoginData): AxiosPromise<LoginResult> {
  return request({
    url: '/api/v1/auth/login',
    method: 'post',
    params: data
  });
}

登录 API 调用

// src/store/modules/user.ts
import { loginApi } from '@/api/auth';
import { LoginData } from '@/api/auth/types';
/**
 * 登录调用
 *
 * @param {LoginData}
 * @returns
 */
function login(loginData: LoginData) {
  return new Promise<void>((resolve, reject) => {
    loginApi(loginData)
      .then(response => {
        const { tokenType, accessToken } = response.data;
        token.value = tokenType + ' ' + accessToken; // Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx
        resolve();
      })
      .catch(error => {
        reject(error);
      });
  });
}


Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(3):

https://developer.aliyun.com/article/1395803

相关文章
|
30天前
|
JavaScript 前端开发 IDE
[译] 用 Typescript + Composition API 重构 Vue 3 组件
[译] 用 Typescript + Composition API 重构 Vue 3 组件
[译] 用 Typescript + Composition API 重构 Vue 3 组件
|
16天前
|
JavaScript 开发工具
vite如何打包vue3插件为JSSDK
【9月更文挑战第10天】以下是使用 Vite 打包 Vue 3 插件为 JS SDK 的步骤:首先通过 `npm init vite-plugin-sdk --template vue` 创建 Vue 3 项目并进入项目目录 `cd vite-plugin-sdk`。接着,在 `src` 目录下创建插件文件(如 `myPlugin.js`),并在 `main.js` 中引入和使用该插件。然后,修改 `vite.config.js` 文件以配置打包选项。最后,运行 `npm run build` 进行打包,生成的 `my-plugin-sdk.js` 即为 JS SDK,可在其他项目中引入使用。
|
1月前
|
JavaScript API
如何使用Vue 3和Type Script进行组件化设计
【8月更文挑战第16天】如何使用Vue 3和Type Script进行组件化设计
32 3
|
1月前
|
JavaScript API
如何使用Vue 3和Type Script进行组件化设计
【8月更文挑战第16天】如何使用Vue 3和Type Script进行组件化设计
38 1
|
1月前
|
JavaScript 前端开发 安全
【Vue3 + Vite】6个非常强大的后台管理项目!开源且免费!
【Vue3 + Vite】6个非常强大的后台管理项目!开源且免费!
|
29天前
|
JavaScript 前端开发 安全
【技术革新】Vue.js + TypeScript:如何让前端开发既高效又安心?
【8月更文挑战第30天】在使用Vue.js构建前端应用时,结合TypeScript能显著提升代码质量和开发效率。TypeScript作为JavaScript的超集,通过添加静态类型检查帮助早期发现错误,减少运行时问题。本文通过具体案例展示如何在Vue.js项目中集成TypeScript,并利用其类型系统提升代码质量。首先,使用Vue CLI创建支持TypeScript的新项目,然后构建一个简单的待办事项应用,通过定义接口描述数据结构并在组件中使用类型注解,确保代码符合预期并提供更好的编辑器支持。
59 0
|
1月前
|
JavaScript 前端开发 安全
解锁Vue3与TypeScript的完美搭档:getCurrentInstance带你高效打造未来前端
【8月更文挑战第21天】Vue3的getCurrentInstance方法作为Composition API的一部分,让开发者能在组件内访问实例。结合TypeScript,可通过定义组件实例类型实现更好的代码提示与类型检查,提升开发效率与代码质量。例如,定义一个带有特定属性(如myData)的组件实例类型,可以在setup中获取并安全地修改这些属性。这种方式确保了一致性和减少了运行时错误,使开发更加高效和安全。
34 0
|
3天前
|
JavaScript
typeScript进阶(9)_type类型别名
本文介绍了TypeScript中类型别名的概念和用法。类型别名使用`type`关键字定义,可以为现有类型起一个新的名字,使代码更加清晰易懂。文章通过具体示例展示了如何定义类型别名以及如何在函数中使用类型别名。
15 1
typeScript进阶(9)_type类型别名
|
3天前
|
JavaScript
typeScript基础(2)_any任意值类型和类型推论
本文介绍了TypeScript中的`any`任意值类型,它可以赋值为其他任何类型。同时,文章还解释了TypeScript中的类型推论机制,即在没有明确指定类型时,TypeScript如何根据变量的初始赋值来推断其类型。如果变量初始化时未指定类型,将被推断为`any`类型,从而允许赋予任何类型的值。
20 4
|
3天前
|
JavaScript
typeScript基础(5)_对象的类型-interfaces接口
本文介绍了TypeScript中接口(interfaces)的基本概念和用法,包括如何定义接口、接口的简单使用、自定义属性、以及如何使用`readonly`关键字定义只读属性。接口在TypeScript中是定义对象形状的重要方式,可以规定对象的必有属性、可选属性、自定义属性和只读属性。
15 1