使用vite构建vue3项目详细介绍(ts+pinia+sass+vue-router+axios+element-plus)

使用vite构建vue3项目详细介绍(ts+pinia+sass+vue-router+axios+element-plus)

1. 创建项目

npm init vite@latest

2. 配置 vite.config.ts

path需要安装--npm install @types/node --save-dev

import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
import { defineConfig, loadEnv, ConfigEnv } from 'vite';

const alias: Record<string, string> = {
	'@': resolve(__dirname, '.', './src') // 设置文件./src路径为 @
};

const viteConfig = defineConfig((mode: ConfigEnv) => {
	const env = loadEnv(mode.mode, process.cwd());
	return {
		plugins: [vue()],
		resolve: { alias },
	    base: mode.command === 'serve' ? './' : env.VITE_PUBLIC_PATH, // 打包路径
		server: {
			host: '0.0.0.0',
			port: env.VITE_PORT as unknown as number, // 服务端口号
			open: true, // 服务启动时是否自动打开浏览器
			hmr:true, // 开启热更新
		},
	};
});

export default viteConfig;

3. 配置 ts.config.json

{
	"compilerOptions": {
	  "target": "ESNext",
	  "useDefineForClassFields": true,
	  "module": "ESNext",
	  "moduleResolution": "Node",
	  "strict": true,
	  "jsx": "preserve",
	  "resolveJsonModule": true,
	  "isolatedModules": true,
	  "esModuleInterop": true,
	  "lib": ["ESNext", "DOM"],
	  "skipLibCheck": true,
	  "noEmit": true,
	  "baseUrl": "." /* 用于设置基础 url,可以帮我们省掉一些多余的路径前缀。 */,
	  "paths": {
		  "/@/*": ["src/*"]
	  } /* 将导入重新映射到相对于“baseUrl”的查找位置的一系列条目。 */,
	},
	"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
	"references": [{ "path": "./tsconfig.node.json" }]
  }
  

新建一个全局的ts文件声明.vue后缀文件 

 4. 配置使用 Sass

npm i sass -D

 5. 配置使用 vue-router

npm i vue-router

创建文件 src/router/route.ts

import { RouteRecordRaw } from 'vue-router';

/**
 * 建议:路由 path 路径与文件夹名称相同,找文件可浏览器地址找,方便定位文件位置
 *
 * 路由meta对象参数说明
 * meta: {
 *      title:          菜单栏及 tagsView 栏、菜单搜索名称(国际化)
 *      isLink:        是否超链接菜单,开启外链条件,`1、isLink: 链接地址不为空 2、isIframe:false`
 *      isHide:        是否隐藏此路由
 *      isKeepAlive:   是否缓存组件状态
 *      isAffix:       是否固定在 tagsView 栏上
 *      isIframe:      是否内嵌窗口,开启条件,`1、isIframe:true 2、isLink:链接地址不为空`
 *      roles:         当前路由权限标识,取角色管理。控制路由显示、隐藏。超级管理员:admin 普通角色:common
 *      icon:          菜单、tagsView 图标,阿里:加 `iconfont xxx`,fontawesome:加 `fa xxx`
 * }
 */

// 扩展 RouteMeta 接口
declare module 'vue-router' {
	interface RouteMeta {
		title?: string;
		isLink?: string;
		isHide?: boolean;
		isKeepAlive?: boolean;
		isAffix?: boolean;
		isIframe?: boolean;
		roles?: string[];
		icon?: string;
	}
}

/**
 * 定义动态路由
 * 前端添加路由,请在顶级节点的 `children 数组` 里添加
 * @description 未开启 isRequestRoutes 为 true 时使用(前端控制路由),开启时第一个顶级 children 的路由将被替换成接口请求回来的路由数据
 * @description 各字段请查看 `/@/views/system/menu/component/addMenu.vue 下的 ruleForm`
 * @returns 返回路由菜单数据
 */
export const dynamicRoutes: Array<RouteRecordRaw> = [
	{
		path: '/',
		name: '/',
		component: () => import('/@/layout/index.vue'),
		redirect: '/home',
		meta: {
			isKeepAlive: true,
		},
		children: [
			{
				path: '/home',
				name: 'home',
				component: () => import('/@/views/home/index.vue'),
				meta: {
					title: 'message.router.home',
					isLink: '',
					isHide: false,
					isKeepAlive: true,
					isAffix: true,
					isIframe: false,
					roles: ['admin', 'common'],
					icon: 'iconfont icon-shouye',
				},
			},
		],
	},
];

/**
 * 定义404、401界面
 * @link 参考:https://next.router.vuejs.org/zh/guide/essentials/history-mode.html#netlify
 */
export const notFoundAndNoPower = [
	{
		path: '/:path(.*)*',
		name: 'notFound',
		component: () => import('/@/views/error/404.vue'),
		meta: {
			title: 'message.staticRoutes.notFound',
			isHide: true,
		},
	},
	{
		path: '/401',
		name: 'noPower',
		component: () => import('/@/views/error/401.vue'),
		meta: {
			title: 'message.staticRoutes.noPower',
			isHide: true,
		},
	},
];

/**
 * 定义静态路由(默认路由)
 * 此路由不要动,前端添加路由的话,请在 `dynamicRoutes 数组` 中添加
 * @description 前端控制直接改 dynamicRoutes 中的路由,后端控制不需要修改,请求接口路由数据时,会覆盖 dynamicRoutes 第一个顶级 children 的内容(全屏,不包含 layout 中的路由出口)
 * @returns 返回路由菜单数据
 */
export const staticRoutes: Array<RouteRecordRaw> = [
	{
		path: '/login',
		name: 'login',
		component: () => import('/@/views/login/index.vue'),
		meta: {
			title: '登录',
		},
	},
];

创建文件src/router/index.ts

import { createRouter, createWebHashHistory } from 'vue-router';
import { staticRoutes, notFoundAndNoPower } from '/@/router/route';

/**
 * 创建一个可以被 Vue 应用程序使用的路由实例
 * @method createRouter(options: RouterOptions): Router
 * @link 参考:https://next.router.vuejs.org/zh/api/#createrouter
 */
export const router = createRouter({
	history: createWebHashHistory(),
	/**
	 * 说明:
	 * 1、notFoundAndNoPower 默认添加 404、401 界面,防止一直提示 No match found for location with path 'xxx'
	 * 2、backEnd.ts(后端控制路由)、frontEnd.ts(前端控制路由) 中也需要加 notFoundAndNoPower 404、401 界面。
	 *    防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
	 */
	routes: [...notFoundAndNoPower, ...staticRoutes],
});

// 导出路由
export default router;

使用:在src/main.ts中导入并注册

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

createApp(App).use(router).mount('#app')

6. 配置使用 Pinia

npm install pinia

 

创建文件 src/stores/index.ts

// https://pinia.vuejs.org/
import { createPinia } from 'pinia';

// 创建
const pinia = createPinia();

// 导出
export default pinia;

创建文件 src/stores/userInfo.ts

import { defineStore } from 'pinia';
import Cookies from 'js-cookie';
import { Session } from '/@/utils/storage';

/**
 * 用户信息
 * @methods setUserInfos 设置用户信息
 */
export const useUserInfo = defineStore('userInfo', {
	state: (): UserInfosState => ({
		userInfos: {
			userName: '',
			photo: '',
			time: 0,
			roles: [],
			authBtnList: [],
		},
	}),
	actions: {
		async setUserInfos() {
			// 存储用户信息到浏览器缓存
			if (Session.get('userInfo')) {
				this.userInfos = Session.get('userInfo');
			} else {
				const userInfos: any = await this.getApiUserInfo();
				this.userInfos = userInfos;
			}
		},
		// 模拟接口数据
		async getApiUserInfo() {
			return new Promise((resolve) => {
				setTimeout(() => {
					// 模拟数据,请求接口时,记得删除多余代码及对应依赖的引入
					const userName = Cookies.get('userName');
					// 模拟数据
					let defaultRoles: Array<string> = [];
					let defaultAuthBtnList: Array<string> = [];
					// admin 页面权限标识,对应路由 meta.roles,用于控制路由的显示/隐藏
					let adminRoles: Array<string> = ['admin'];
					// admin 按钮权限标识
					let adminAuthBtnList: Array<string> = ['btn.add', 'btn.del', 'btn.edit', 'btn.link'];
					// test 页面权限标识,对应路由 meta.roles,用于控制路由的显示/隐藏
					let testRoles: Array<string> = ['common'];
					// test 按钮权限标识
					let testAuthBtnList: Array<string> = ['btn.add', 'btn.link'];
					// 不同用户模拟不同的用户权限
					if (userName === 'admin') {
						defaultRoles = adminRoles;
						defaultAuthBtnList = adminAuthBtnList;
					} else {
						defaultRoles = testRoles;
						defaultAuthBtnList = testAuthBtnList;
					}
					// 用户信息模拟数据
					const userInfos = {
						userName: userName,
						photo: 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500',
						time: new Date().getTime(),
						roles: defaultRoles,
						authBtnList: defaultAuthBtnList,
					};
					resolve(userInfos);
				}, 0);
			});
		},
	},
});

使用:在 src/main.ts中导入并注册

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import pinia from '/@/stores/index'

createApp(App).use(pinia).use(router).mount('#app')

7. 配置使用 Axios

npm i axios

创建文件 src/utils/request.ts

import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Session } from '/@/utils/storage'
import qs from 'qs'

// 配置新建一个 axios 实例
const service: AxiosInstance = axios.create({
	baseURL: import.meta.env.VITE_API_URL,
	timeout: 50000,
	headers: { 'Content-Type': 'application/json' },
	paramsSerializer: {
		serialize(params) {
			return qs.stringify(params, { allowDots: true })
		},
	},
})

// 添加请求拦截器
service.interceptors.request.use(
	(config: AxiosRequestConfig) => {
		// 在发送请求之前做些什么 token
		if (Session.get('token')) {
			config.headers!['Authorization'] = `${Session.get('token')}`
		}
		return config
	},
	(error) => {
		// 对请求错误做些什么
		return Promise.reject(error)
	}
)

// 添加响应拦截器
service.interceptors.response.use(
	(response) => {
		// 对响应数据做点什么
		const res = response.data
		if (res.code && res.code !== 0) {
			// `token` 过期或者账号已在别处登录
			if (res.code === 401 || res.code === 4001) {
				Session.clear() // 清除浏览器全部临时缓存
				window.location.href = '/' // 去登录页
				ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
					.then(() => {})
					.catch(() => {})
			}
			return Promise.reject(service.interceptors.response)
		} else {
			return response.data
		}
	},
	(error) => {
		// 对响应错误做点什么
		if (error.message.indexOf('timeout') != -1) {
			ElMessage.error('网络超时')
		} else if (error.message == 'Network Error') {
			ElMessage.error('网络连接错误')
		} else {
			if (error.response.data) ElMessage.error(error.response.statusText)
			else ElMessage.error('接口路径找不到')
		}
		return Promise.reject(error);
	}
);

// 导出 axios 实例
export default service

8. 配置使用 elementplus

npm i element-plus --save

使用:在 src/main.ts中导入并注册

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import pinia from '/@/stores/index'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

createApp(App).use(pinia).use(router).use(ElementPlus).mount('#app')

猜你喜欢

转载自blog.csdn.net/qq243348167/article/details/128671626