这是b站上尚硅谷分享的基于Vue3+Ts的前端项目《硅谷甄选》,使用的脚手架为Vite,从零开始,进行环境配置,再到项目的实现。
由于视频是2023年发布的,至今技术也进行了各种更新,所以有些地方我也会用新知识去替代视频中的内容。
项目较大,本期先总结环境配置的部分。
一、创建Vue应用
我使用的包管理器是npm:
npm create vue@latest
初始化配置如下:
接着根据提示完成创建(现在的Vite比较先进,能够自动配置ESLint和Prettier,无需手动配置)。创建完成后手动删除多余的、无用的文件和代码。
二、项目集成
1.集成Element Plus
安装:
npm install element-plus --save
引入:
main.js:
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus, {
locale: zhCn, // 中文
})
2.环境变量配置
在根目录下添加开发、生产和测试环境的文件
.env.development:
NODE_ENV = 'development'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/api'
VITE_SERVE = 'http://xxx.com'
.env.production:
NODE_ENV = 'production'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/prod-api'
VITE_SERVE = 'http://yyy.com'
.env.test
NODE_ENV = 'test'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/test-api'
VITE_SERVE = 'http://zzz.com'
运行配置:
package.json:
"scripts": {
"build:test": "vue-tsc && vite build --mode test",
"build:pro": "vue-tsc && vite build --mode production",
},
3.svg图标配置
安装依赖:
npm install vite-plugin-svg-icons -D
创建存放图标的文件夹:
配置:
vite.config.ts:
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
plugins: [
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], // svg图标地址
symbolId: 'icon-[dir]-[name]',
}),
],
main.ts:
// svg 插件需要配置代码
import 'virtual:svg-icons-register'
import SvgIcon from '@/components/SvgIcon/index.vue'
4.svg封装为全局组件
新建SvgIcon组件
封装:
index.vue:
<!-- 封装 svg 图标组件 -->
<template>
<div>
<svg :style={width,height}>
<use :xlink:href="prefix + name" :fill="color"></use>
</svg>
</div>
</template>
<script setup lang="ts">
defineProps({
prefix:{
type:String,
default:'#icon-'
},
name:String,
color:{
type:String,
default:''
},
width:{
type:String,
default:'16px'
},
height:{
type:String,
default:'16px'
}
})
</script>
<style scoped></style>
因为用的地方比较多,注册为全局组件更方便:
main.ts:
import SvgIcon from '@/components/SvgIcon/index.vue'
app.component('SvgIcon', SvgIcon)
测试代码:
<svg-icon name="duck" color="" width="60px" height="60px"></svg-icon>
5.集成sass
安装依赖:
npm install -D sass
在src下创建样式文件:
在npm官网上复制reset.scss文件;
引入:
index.scss:
// 引入清除默认样式
@use './reset.scss'
main.ts:
// 引入 scss 样式
import '@/styles/index.scss'
引入全局变量:
variable.scss
$pri-color: hotpink;
配置全局变量:
vite.config.ts:
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "@/styles/variable.scss" as *;',
},
},
}
})
6.配置mock数据
安装依赖:
npm i vite-plugin-mock
配置mock:
vite.config.js:
import { viteMockServe } from 'vite-plugin-mock'
plugins: [
viteMockServe({
enable: true, // 启用本地mock
})
],
根目录创建mock文件夹:
创建接口文件:
user.ts:
// 用户信息数据
// createUserList: 此函数执行会返回一个数组,数组里面包含两个用户信息
function createUserList() {
return [
{
userId: 1,
avatar:
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
username: 'admin',
password: '111111',
desc: '平台管理员',
roles: ['平台管理员'],
buttons: ['cuser.detail'],
routes: ['home'],
token: 'Admin Token',
},
{
userId: 2,
avatar:
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
username: 'system',
password: '111111',
desc: '系统管理员',
roles: ['系统管理员'],
buttons: ['cuser.detail', 'cuser.user'],
routes: ['home'],
token: 'System Token',
},
]
}
// 对外暴露一个数组:数组里面包含两个接口
// 登录假的接口
// 获取用户信息的假的接口
export default [
// 用户登录接口
{
url: '/api/user/login',//请求地址
method: 'post',//请求方式
response: ({ body }) => {
//获取请求体携带过来的用户名与密码
const { username, password } = body;
//调用获取用户信息函数,用于判断是否有此用户
const checkUser = createUserList().find(
(item) => item.username === username && item.password === password,
)
//没有用户返回失败信息
if (!checkUser) {
return { code: 201, data: { message: '账号或者密码不正确' } }
}
//如果有返回成功信息
const { token } = checkUser
return { code: 200, data: { token } }
},
},
// 获取用户信息
{
url: '/api/user/info',
method: 'get',
response: (request) => {
//获取请求头携带token
const token = request.headers.token;
//查看用户信息是否包含有次token用户
const checkUser = createUserList().find((item) => item.token === token)
//没有返回失败的信息
if (!checkUser) {
return { code: 201, data: { message: '获取用户信息失败' } }
}
//如果有返回成功信息
return { code: 200, data: { checkUser } }
},
},
]
测试接口:
main.ts:
// 测试接口
import axios from 'axios'
axios({
url: '/api/user/login',
method: 'post',
data: {
username: 'admin',
password: '111111'
}
})
7.axios二次封装
src下创建utils/request.ts :
结合axios和element-plus封装request:
request.ts:
// 进行 axios 的二次封装:使用请求和响应拦截器
import axios from "axios";
import { ElMessage } from "element-plus";
// 一、利用 axios 的 create 方法,去创建 axios 实例(其他配置:基础路径、超时时间)
const request = axios.create({
// 基础路径
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 5000
})
// 二、request 实例添加请求与响应拦截器
request.interceptors.request.use((config) => {
// config 配置对象,header 属性请求头,经常给服务器端携带参数
// config.headers.token = "111"
// 返回配置对象
return config;
})
// 三、响应拦截器
request.interceptors.response.use((response) => {
// 成功回调
// 简化数据
return response.data;
}, (error) => {
// 失败回调,处理http网络错误
// 定义一个变量-存储网络错误信息
let message = ''
// http状态码
let status = error.response.status;
switch (status) {
case 401:
message = "TOKEN过期"
break;
case 403:
message = "无权访问"
break;
case 404:
message = "请求地址错误"
break;
case 500:
message = "服务器出现问题"
break;
default:
message = "网络出现问题"
break;
}
// 提示错误信息
ElMessage({
type: 'error',
message
})
return Promise.reject(error)
})
// 暴露
export default request
测试:
App.vue:
// request 测试
import request from './utils/request'
import { onMounted } from 'vue'
onMounted(() => {
request({
url: '/user/login11',
method: 'post',
data: {
username: 'admin',
password: '111111'
}
}).then(res => {
console.log(res);
}).catch(error=>{
console.log(error);
})
})
8.api接口统一管理
创建api接口管理文件:
用户接口管理:
user/index.ts:
// 统一管理项目用户相关接口
import request from "@/utils/request";
import type { loginForm, loginResponseData, userResponseData } from "./type";
// 统一管理接口
enum API {
LOGIN_URL = "/user/login",
USERINFO_URL = "user/info"
}
// 暴露请求函数
// 登录接口方法
export const reqLogin = (data: loginForm) => request.post<any, loginResponseData>(API.LOGIN_URL, data)
// 获取用户信息接口方法
export const reqUserInfo = () => request.get<any, userResponseData>(API.USERINFO_URL)
类型约束:
user/type.ts:
// 登录接口需要携带的ts类型
export interface loginForm {
username: string,
password: string
}
interface dataType {
token: string
}
// 登录接口返回的数据类型
export interface loginResponseData {
code: number,
data: dataType
}
interface userInfo {
userId: number,
avatar: string
username: string,
password: string,
desc: string,
roles: string[],
buttons: string[],
routes: string[],
token: string,
}
// 定义服务器返回用户信息相关的数据类型
interface user {
checkUser: userInfo
}
export interface userResponseData {
code: number
data: user
}
测试:
App.vue:
// 接口测试
import { reqLogin } from './api/user';
onMounted(()=>{
reqLogin({username:'admin',password:'1111111'})
})
9.路由配置
创建路由文件:
配置路由(我用的是 HTML5 模式):
router/index.ts:
import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/views/login/Login.vue'
import Home from '@/views/home/Home.vue'
import Not from '@/views/404/Not.vue'
// 创建路由器
const router = createRouter({
// 路由模式
history: createWebHistory(),
routes: [
{
path: '/login',
component: Login
},
{
path: '/home',
component: Home
},
{
path: '/404',
component: Not
},
// 重定向
{
path: '/',
redirect: 'home'
},
// 任意路由
{
path: '/:pathMatch(.*)*',
redirect: '404'
}
],
//滚动行为
scrollBehavior() {
return {
left: 0,
top: 0
}
}
})
// 暴露
export default router
10.pinia配置
创建store文件夹:
index.ts:
import { createPinia } from 'pinia'
const pinia = createPinia()
export default pinia
应用:
main.ts:
import pinia from './store'
app.use(pinia)
三、小结
总之,项目初期,环境配置是一个大量且繁琐的工程,但有至关重要,需要耐心对待。