Vue3搭建记录

news/2024/4/25 22:03:30/文章来源:https://blog.csdn.net/wenxingchen/article/details/129108134

一、初始化项目:项目名称vue3-element-admin

npm init vite@latest vue3-element-admin --template vue-ts

 二、整合Element-Plus

 1.本地安装Element Plus和图标组件

npm install element-plus
npm install @element-plus/icons-vue

 2.全局注册组件

// main.ts
import ElementPlus from 'element-plus'
import 'element-plus/theme-chalk/index.css'createApp(App).use(ElementPlus).mount('#app')

 3.Element Plus全局组件类型声明

// tsconfig.json
{"compilerOptions": {// ..."types": ["element-plus/global"]}
}

 4.页面使用

<el-button type="primary">登录</el-button>

 

三、 路径别名配置:使用 @ 代替 src

1. 安装@types/node

npm install @types/node --save-dev

2. Vite配置

// vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'import path from 'path'export default defineConfig({plugins: [vue()],resolve: {alias: {"@": path.resolve("./src") // 相对路径别名配置,使用 @ 代替 src}}
})

3. TypeScript 编译配置

// tsconfig.json
{"compilerOptions": {"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录"paths": { //路径映射,相对于baseUrl"@/*": ["src/*"] },"allowSyntheticDefaultImports": true // 允许默认导入}
}

4.别名使用

四、多环境配置

1. 项目根目录:分别添加
开发环境:.env.development
生产环境:.env.production
测试环境:.env.test

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

2.WebStorm插件

3.环境变量智能提示 

在src下新建文件env.d.ts,内容如下:

// src/ env.d.ts
// 环境变量类型声明
interface ImportMetaEnv {VITE_APP_TITLE: string,VITE_APP_PORT: string,VITE_APP_BASE_API: string
}interface ImportMeta {readonly env: ImportMetaEnv
}

五、Vite 配置反向代理解决跨域

修改vite.config.ts文件为如下:

// vite.config.ts
import {UserConfig, ConfigEnv, loadEnv} from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'export default ({command, mode}: ConfigEnv): UserConfig => {// 获取 .env 环境配置文件const env = loadEnv(mode, process.cwd())return ({plugins: [vue()],// 本地反向代理解决浏览器跨域限制server: {host: 'localhost',port: Number(env.VITE_APP_PORT),open: true, // 启动是否自动打开浏览器proxy: {[env.VITE_APP_BASE_API]: {target: 'http://vapi.youlai.tech', // 有来商城线上接口地址changeOrigin: true,rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')}}},resolve: {alias: {"@": path.resolve("./src") // 相对路径别名配置,使用 @ 代替 src}}})
}

F12我们看到访问的是本地,实际上内部已经将http://localhost:3000/dev-api/换成了http://vapi.youlai.tech/


至此基本环境搭建已经搭建成功,接下来是三大件的集成:Pinia、Axios、Vue-router。

三大件是项目交叉依赖的,Pinia需要存储用户信息,用户信息需要Axios来获取,Vue-router需要Axios来获取角色等等。所以只有三大件完全组件完毕才能启动成功!

npm install better-scroll -S
npm install echarts --save
npm install sass
npm install -D path-browserify
npm install -D path-to-regexp
npm install @wangeditor/editor-for-vue@next
npm install vue-i18n@next

六、Pinia状态管理

1. 安装Pinia

npm install pinia

2. Pinia全局注册

在src下新建store文件夹,然后在store文件夹下新建index.ts内容如下:

// src/store/index.ts
import type { App } from 'vue';
import { createPinia } from 'pinia';const store = createPinia();// 全局挂载store
export function setupStore(app: App<Element>) {app.use(store);
}export { store };

 修改main.ts为如下:

// src/main.ts
import {createApp} from 'vue'
import './style.css'
import App from './App.vue'import ElementPlus from 'element-plus'
import 'element-plus/theme-chalk/index.css'import {setupStore} from '@/store';const app = createApp(App);
// 全局挂载
setupStore(app);app.use(ElementPlus).mount('#app');

3.Pinia模块封装

在store文件夹下新建modules文件夹,这里以用户状态为例:在modules文件夹下新建user文件夹,在于user文件夹下新建index.ts和types.ts内容如下:

// src/store/modules/user/index.ts
import { defineStore } from 'pinia';import { store } from '@/store';
import { ref } from 'vue';export const useUserStore = defineStore('user', () => {// stateconst token = ref<string>('');const nickname = ref<string>('');const avatar = ref<string>('');const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限const perms = ref<Array<string>>([]); // 用户权限编码集合 → 判断按钮权限// actions// 登录function login(loginData: any) {return new Promise<void>((resolve, reject) => {console.log(loginData)// loginApi(loginData) // 调用登录API});}// 获取信息(用户昵称、头像、角色集合、权限集合)function getInfo() {return new Promise<any>((resolve, reject) => {// getUserInfo() // 调用获取用户信息API});}// 注销function logout() {return new Promise<void>((resolve, reject) => {// logoutApi() // 调用注销API});}// 重置function resetToken() {// removeToken(); 调用删除Token方法token.value = '';nickname.value = '';avatar.value = '';roles.value = [];perms.value = [];}return {token,nickname,avatar,roles,perms,login,getInfo,logout,resetToken};
});// 非setup
export function useUserStoreHook() {return useUserStore(store);
}

4.使用Pinia 

①setup调用

②非setup调用

七、Axios网络请求库封装

1. 安装Axios和js-cookie

npm install --save js-cookie
npm install --save @types/js-cookie
npm install axios

2.axios工具封装

在src下新建utils文件夹,然后在utils文件下新建auth.ts、localStorage.ts、request.ts,内容如下:

// src/utils/auth.ts
import Cookies from 'js-cookie';const TokenKey = 'vue3-element-admin-token';export function getToken() {return Cookies.get(TokenKey);
}export function setToken(token: string) {Cookies.set(TokenKey, token);
}export function removeToken() {return Cookies.remove(TokenKey);
}
// src/utils/request.ts
import axios, { AxiosRequestConfig,InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
import { getToken } from '@/utils/auth';
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<any>) => {if (!config.headers) {throw new Error(`Expected 'config' and 'config.headers' not to be undefined`);}const user = useUserStoreHook();if (user.token) {(config.headers as any).Authorization = getToken();}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;} else {// 响应数据为二进制流处理(Excel导出)if (response.data instanceof ArrayBuffer) {return response;}ElMessage({message: msg || '系统出错',type: 'error'});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: 'OK',type: 'warning'}).then(() => {localStorage.clear();window.location.href = '/';});} else {ElMessage({message: msg || '系统出错',type: 'error'});}}return Promise.reject(error.message);}
);// 导出 axios 实例
export default service;

3.API封装

以登录、并获取用户信息(昵称、头像、角色集合和权限集合)的接口为案例,演示如何通过封装的 axios 工具类请求后端接口,获取响应数据。

在src下新建types文件夹,然后在types文件夹下新建global.d.ts内容如下:

declare global {interface PageQuery {pageNum: number;pageSize: number;}interface PageResult<T> {list: T;total: number;}type DialogType = {title?: string;visible: boolean;};type OptionType = {value: string;label: string;checked?: boolean;children?: OptionType[];};
}
export {};

在src下新建api文件夹,然后在api下新建auth文件夹,然后在auth文件夹下新建index.ts和types.ts,内容如下:

// src/api/auth/index.ts
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { LoginData, TokenResult, VerifyCode } from './types';/**** @param data {LoginForm}* @returns*/
export function loginApi(data: LoginData): AxiosPromise<TokenResult> {return request({url: '/api/v1/auth/login',method: 'post',params: data});
}/*** 注销*/
export function logoutApi() {return request({url: '/api/v1/auth/logout',method: 'delete'});
}/*** 获取图片验证码*/
export function getCaptcha(): AxiosPromise<VerifyCode> {return request({url: '/captcha?t=' + new Date().getTime().toString(),method: 'get'});
}
// src/api/auth/types.ts
/*** 登录数据类型*/
export interface LoginData {username: string;password: string;/*** 验证码Code*///verifyCode: string;/*** 验证码Code服务端缓存key(UUID)*/// verifyCodeKey: string;
}/*** Token响应类型*/
export interface TokenResult {accessToken: string;refreshToken: string;expires: number;
}/*** 验证码类型*/
export interface VerifyCode {verifyCodeImg: string;verifyCodeKey: string;
}

在api下新建user文件夹,然后在user文件夹下新建index.ts和types.ts,内容如下:

// src/api/user/index.ts
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { UserForm, UserInfo, UserPageResult, UserQuery } from './types';/*** 登录成功后获取用户信息(昵称、头像、权限集合和角色集合)*/
export function getUserInfo(): AxiosPromise<UserInfo> {return request({url: '/api/v1/users/me',method: 'get'});
}/*** 获取用户分页列表** @param queryParams*/
export function listUserPages(queryParams: UserQuery
): AxiosPromise<UserPageResult> {return request({url: '/api/v1/users/pages',method: 'get',params: queryParams});
}/*** 获取用户表单详情** @param userId*/
export function getUserForm(userId: number): AxiosPromise<UserForm> {return request({url: '/api/v1/users/' + userId + '/form',method: 'get'});
}/*** 添加用户** @param data*/
export function addUser(data: any) {return request({url: '/api/v1/users',method: 'post',data: data});
}/*** 修改用户** @param id* @param data*/
export function updateUser(id: number, data: UserForm) {return request({url: '/api/v1/users/' + id,method: 'put',data: data});
}/*** 修改用户状态** @param id* @param status*/
export function updateUserStatus(id: number, status: number) {return request({url: '/api/v1/users/' + id + '/status',method: 'patch',params: { status: status }});
}/*** 修改用户密码** @param id* @param password*/
export function updateUserPassword(id: number, password: string) {return request({url: '/api/v1/users/' + id + '/password',method: 'patch',params: { password: password }});
}/*** 删除用户** @param ids*/
export function deleteUsers(ids: string) {return request({url: '/api/v1/users/' + ids,method: 'delete'});
}/*** 下载用户导入模板** @returns*/
export function downloadTemplate() {return request({url: '/api/v1/users/template',method: 'get',responseType: 'arraybuffer'});
}/*** 导出用户** @param queryParams* @returns*/
export function exportUser(queryParams: UserQuery) {return request({url: '/api/v1/users/_export',method: 'get',params: queryParams,responseType: 'arraybuffer'});
}/*** 导入用户** @param file*/
export function importUser(deptId: number, roleIds: string, file: File) {const formData = new FormData();formData.append('file', file);formData.append('deptId', deptId.toString());formData.append('roleIds', roleIds);return request({url: '/api/v1/users/_import',method: 'post',data: formData,headers: {'Content-Type': 'multipart/form-data'}});
}
// src/api/user/types.ts
/*** 登录用户信息*/
export interface UserInfo {nickname: string;avatar: string;roles: string[];perms: string[];
}/*** 用户查询参数*/
export interface UserQuery extends PageQuery {keywords: string;status: number;deptId: number;
}/*** 用户分页列表项声明*/
export interface UserType {id: string;username: string;nickname: string;mobile: string;gender: number;avatar: string;email: string;status: number;deptName: string;roleNames: string;createTime: string;
}/*** 用户分页项类型声明*/
export type UserPageResult = PageResult<UserType[]>;/*** 用户表单类型声明*/
export interface UserForm {id: number | undefined;deptId: number;username: string;nickname: string;password: string;mobile: string;email: string;gender: number;status: number;remark: string;roleIds: number[];
}/*** 用户导入表单类型声明*/
export interface UserImportData {deptId: number;roleIds: number[];
}

4. API调用

 

 

八、路由vue-router

1.安装 vue-router

npm install vue-router@next

2. 创建路由实例

创建路由实例并导出,其中包括静态路由数据,动态路由后面将通过接口从后端获取并整合用户角色的权限控制。

①.在src下新建router文件夹,在router文件夹下新建index.ts内容如下:

②.在src下新建views文件夹,并在views下新建文件夹dashboard、login、redirect,以及相应的index.vue文件,在views下新建文件夹error-page并在其中新建404.vue、401.vue.
③在api文件夹下新建menu文件夹,并在其中新建index.ts和types.ts

④在根目录下新建types文件夹,并在其中新建global.d.ts内容如下:

 ③修改store/index.ts为如下

④在src文件夹下新建global.d.ts内容如下:

③.在store/modules文件夹下新建user和permission文件夹,并分别在其中新建index.ts内容如下

3. 路由实例全局注册

// main.ts
import router from "@/router";app.use(router).mount('#app')

4. 动态权限路由

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_71677.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode】No.232. 用栈实现队列 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/implement-queue-using-stacks/ 1. 题目介绍&#xff08;232. 用栈实现队列&#xff09; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff…

【前端】小程序开发入门:安装开发工具、目录结构与项目配置

文章目录前期准备目录结构app.jsonpageswindow其他前期准备 开发小程序要先申请一个对应的AppID&#xff1a;微信小程序 (qq.com) 微信官方小程序开发文档&#xff1a;微信开放文档 (qq.com) 然后安装一个小程序开发工具&#xff1a; 选择稳定版&#xff1a; 安装后打开&…

如何在SpringBoot项目上让接口返回数据脱敏,一个注解即可

1 背景需求是某些接口返回的信息&#xff0c;涉及到敏感数据的必须进行脱敏操作2 思路①要做成可配置多策略的脱敏操作&#xff0c;要不然一个个接口进行脱敏操作&#xff0c;重复的工作量太多&#xff0c;很显然违背了“多写一行算我输”的程序员规范。思来想去&#xff0c;定…

【linux】——gcc/g++,make/makefile的简单使用

目录 1.gcc的基本使用 2.Linux下的静态库和动态库的理解 3.Linux项目自动化构建工具——make/makefile 1.gcc的基本使用 gcc是专门用来编译c语言的 g是专门用来编译c的&#xff0c;但是g也能够用来编译c语言 预处理&#xff08;进行宏替换&#xff09; 预处理功能主要包括宏…

【前端提效】-- VsCode 实用插件推荐

EditorConfig for VS Code ***** 作用&#xff1a;多人协同开发&#xff0c;规范缩进风格&#xff0c;缩进大小&#xff0c;tab长度以及字符集等&#xff0c;解决不同IDE的编码范设置&#xff0c;在这里配置&#xff08;.editorconfig&#xff09;的代码规范规则优先级高于编辑…

java诊断与调优常用命令jmap、jstack、jstat使用实战

java应用运行过程中难免会出现问题&#xff0c;特别是在生产环境&#xff0c;发生异常或宕机情况&#xff0c;需要诊断与分析&#xff0c;定位原因&#xff0c;进行优化&#xff0c;避免下次再次出现问题。 虽然现在有很多可视化工具&#xff0c;使用起来比命令行更方便&#x…

Julia 语言环境安装

Julia 语言支持以下系统&#xff1a; LinuxFreeBSDmacOSWindowsAndroid Julia 安装包下载地址为&#xff1a;Download Julia。 Github 源码地址&#xff1a;GitHub - JuliaLang/julia: The Julia Programming Language。 国内镜像地址&#xff1a;Index of /julia-releases/…

逻辑回归—二元分类问题的操作顺序

对于二元分类问题来说&#xff0c;分类的结果和数据的特征之间仍呈现相关关系&#xff0c;但是y的值不再是连续的&#xff0c;是0&#xff5e;1的跃迁。但是在这个过程中&#xff0c;什么仍然是连续的呢&#xff1f;”是概率&#xff0c;概率是逐渐升高的&#xff0c;当达到一个…

AI制药 - TMScore(US-align)、RMSD、Sequence 源码

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/129125467 参考文档:Nature Methods | 蛋白、RNA、DNA及其复合物结构的比对算法US-align 官网地址:https://zhanggroup.org/US-align/ TMScore TMScore,…

文件系统与动静态库的基本了解

目录文件系统与动静态库的基本了解文件系统了解Access Modify Changeinode硬链接软链接静态库与动态库概念静态库的制作使用静态库动态库的制作使用动态库总结如何制作文件系统与动静态库的基本了解 文件系统 了解Access Modify Change 当文件没有被打开时&#xff0c;他们存…

数据挖掘,计算机网络、操作系统刷题笔记50

数据挖掘&#xff0c;计算机网络、操作系统刷题笔记50 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;orac…

(考研湖科大教书匠计算机网络)第五章传输层-第八节1:TCP连接管理理论部分(三次握手与四次挥手)

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航此部分内容借鉴博主【小林coding】 &#xff0c;其对计算机网络内容的图解可以说是深入浅出&#xff0c;尤其是三次握手和四次挥手这一部分&#xff0c;堪称全网最佳。所这…

webpack5打包工具的使用

目录 -----------------------------基础篇------------------------------- 一、为什么需要打包工具 二、基本使用 1、模式 2、使用步骤 三、基本配置 1、五大核心概念 2、准备 Webpack 配置文件 3、运行指令 四、开发模式 五、处理样式资源 1、处理CSS资源 2、处…

100份简历才找一个合适的,2023,软件测试岗位饱和了吗?

各大互联网公司的接连裁员&#xff0c;政策限制的行业接连消失&#xff0c;让今年的求职雪上加霜&#xff0c;想躺平却没有资本&#xff0c;还有人说软件测试岗位饱和了&#xff0c;对此很多求职者深信不疑&#xff0c;因为投出去的简历回复的越来越少了。 另一面企业招人真的…

闪光桐人の实习日记(2023年2月20-27日)

前往闪闪の小窝以获得更好的阅读和评论体验 文章目录2023年2月20日&#xff08;Vue入门&#xff09;概念Vue基础Vue中的MVVMVue的体验Vue的生命周期Vue指令Vue组件VueRouter前后端路由的区别工作原理两种模式比较route跟router的区别路由属性导航守卫Vuex概述5种基本对象基本使…

Qt线程QThread详解

目录前言1.QThread介绍2.QThread示例一3.QThread示例二4.线程同步前言 在程序中使用线程可以提高程序的性能、并发性、响应性和稳定性&#xff0c;使得程序设计更加灵活和简单。但是&#xff0c;线程编程也有一些挑战&#xff0c;如线程安全性和死锁等问题需要格外注意。我们使…

【1】linux命令每日分享——mkdir

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…

【机器学习】决策树-ID3算法

1.ID3算法 ID3算法利用信息增益进行特征的选择进行树的构建。信息熵的取值范围为0~1&#xff0c;值越大&#xff0c;越不纯&#xff0c;相反值越小&#xff0c;代表集合纯度越高。信息增益反映的是给定条件后不确定性减少的程度。每一次对决策树进行分叉选取属性的时候&#x…

网络计划--时间参数的计算和优化

根据网络图的基本概念和原则绘制出网络图之后&#xff0c;我们可以计算网络图中有关的时间参数&#xff0c;主要目的是找出关键路线&#xff0c;为网络计划的优化、调整和执行提供明确的时间概念。如下图中从始点①到终点⑧共有4条路线&#xff0c;可以分别计算出每条路线所需的…

使用maven搭建父子工程项目

创建父子工程&#xff0c;可以通过父工程来引入jar&#xff0c;定义统一的版本号等。更方便对整个项目的jar包实现统一化管理&#xff0c;让项目的层次更加清晰。一、创建父工程第一步&#xff1a;file–>new–>project–>maven默认使用jdk1.8&#xff0c;不引入任何j…