作为一名大三前端学习者,在开发 Vue3 实战项目的过程中,近段时间我重点深耕了 Vue3 框架核心能力——路由、状态管理、接口封装,这些都是企业级项目必备的技能,也是实习面试的高频考点。本文整合这段时间的学习与实战经验,结合通用 Vue3 项目场景,分享最实用的 Vue3 知识点,拒绝空谈理论,全是能直接落地的实战内容,适合前端新手参考学习。
一、Vue Router4 实战:路由守卫与懒加载(项目的“导航核心”)
在 Vue3 项目中,路由是页面跳转的核心,既要控制登录权限,也要优化首屏加载速度,这就用到了路由守卫和懒加载两个关键功能,适用于各类中后台、展示类项目。
1. 核心知识点
- 路由懒加载:将路由组件按需加载,减小首屏打包体积,提升加载速度;
- 路由守卫:控制路由跳转权限,实现登录拦截、页面访问限制,最常用全局前置守卫;
- 路由传参:params、query 两种方式,适配不同场景(如传递详情ID、查询条件)。
2. 项目实战代码
(1)路由懒加载配置(必用)
之前直接导入所有路由组件,首屏加载很慢,改用懒加载后,首屏加载速度提升了40%,通用项目代码如下:
dex.js
import { createRouter, createWebHistory } from 'vue-router';
// 路由懒加载:访问对应路由时才加载组件
const Login = () => import('@/views/Login.vue');
const Home = () => import('@/views/Home.vue');
const ListPage = () => import('@/views/ListPage.vue'); // 列表页
const DetailPage = () => import('@/views/DetailPage.vue'); // 详情页
const routes = [
{ path: '/', redirect: '/home' },
{ path: '/login', component: Login },
{ path: '/home', component: Home },
{ path: '/list', component: ListPage },
{ path: '/detail/:id', component: DetailPage } // 动态路由传参
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
(2)全局前置守卫(登录拦截)
通用项目要求:未登录用户不能访问首页、列表等核心页面,必须跳转至登录页,代码如下:
// router/index.js
router.beforeEach((to, from, next) => {
// 从localStorage获取token,判断是否登录
const token = localStorage.getItem('token');
// 白名单:不需要登录就能访问的页面(只有登录页)
const whiteList = ['/login'];
if (whiteList.includes(to.path)) {
next(); // 放行
} else {
// 已登录放行,未登录跳登录页
token ? next() : next('/login');
}
});
3. 项目实战场景与面试点
- 实战场景:访问详情页时,通过动态路由传递数据ID,在详情页接收并请求对应数据;登录后跳转至首页,未登录拦截所有核心页面,适用于各类需要权限控制的项目。
- 面试高频问法:① 路由懒加载的实现方式和好处?② 如何实现Vue路由的登录拦截?③ 动态路由传参和query传参的区别?
- 面试答案:懒加载用import动态导入,好处是减小首屏体积、提升加载速度;登录拦截用全局前置守卫,判断token是否存在;动态路由传参(params)参数在URL路径中,query传参在URL查询字符串中,前者刷新页面参数不丢失(需配置路由),后者会丢失。
二、Pinia 实战:Vue3 状态管理的最优解
在 Vue3 项目中,用户信息、全局主题、加载状态等需要在多个组件间共享的数据,用Pinia管理最简洁高效。之前尝试过Vuex,对比后发现Pinia更轻量、更适合Vue3,也更符合面试趋势,适用于各类需要全局状态共享的项目。
1. 核心知识点
- Pinia 核心:defineStore(定义仓库)、state(状态)、actions(同步/异步操作)、getters(计算属性);
- 优势:无mutations(简化代码)、天生支持TS、体积小(约1KB)、模块化无需额外配置;
- 与Vuex区别:Pinia去掉mutations,actions可写异步,代码更简洁,TS支持更好,无需modules拆分模块。
2. 项目实战代码
(1)定义Pinia仓库(用户信息仓库)
// store/userStore.js
import { defineStore } from 'pinia';
// 定义仓库,第一个参数是仓库唯一标识,第二个参数是配置
export const useUserStore = defineStore('user', {
state: () => ({
token: localStorage.getItem('token') || '', // 用户token
username: localStorage.getItem('username') || '', // 用户名
role: localStorage.getItem('role') || 'user' // 用户角色
}),
actions: {
// 同步设置用户信息
setUserInfo(userInfo) {
this.token = userInfo.token;
this.username = userInfo.username;
this.role = userInfo.role;
// 持久化存储到localStorage,防止页面刷新丢失
localStorage.setItem('token', userInfo.token);
localStorage.setItem('username', userInfo.username);
localStorage.setItem('role', userInfo.role);
},
// 异步退出登录(清除状态)
async logout() {
// 调用退出登录接口
await $axios.post('/api/user/logout');
// 清除仓库状态
this.token = '';
this.username = '';
this.role = 'user';
// 清除localStorage
localStorage.removeItem('token');
localStorage.removeItem('username');
localStorage.removeItem('role');
}
},
getters: {
// 计算属性:判断是否为管理员
isAdmin() {
return this.role === 'admin';
}
}
});
(2)组件中使用Pinia
<template>
<div class="user-info">
<span>{{ username }}</span>
<button @click="handleLogout" v-if="isAdmin">退出登录</button>
</div>
</template>
<script setup>
import { useUserStore } from '@/store/userStore';
import { useRouter } from 'vue-router';
// 获取仓库实例
const userStore = useUserStore();
const router = useRouter();
// 解构仓库状态和方法(可直接使用)
const { username, isAdmin, logout } = userStore;
// 退出登录
const handleLogout = () => {
logout();
router.push('/login');
};
</script>
3. 项目实战场景与面试点
- 实战场景:登录后存储用户信息,在导航栏显示用户名;管理员角色可查看更多操作按钮;退出登录时清除状态并跳转登录页,适用于各类有用户权限管理的项目。
- 面试高频问法:① Pinia和Vuex的区别?② Pinia的actions为什么能写异步?③ 如何实现Pinia状态持久化?
- 面试答案:Pinia无mutations、支持TS、体积小,Vuex有mutations、TS支持差、需modules;Pinia的actions无需像Vuex那样区分同步异步,可直接写async/await;状态持久化可结合localStorage(手动存储)或pinia-plugin-persistedstate插件。
三、Vue3 工程化:axios封装 + 跨域解决(项目的“接口核心”)
Vue3 项目中通常需要大量接口请求:登录、获取列表数据、上传文件、提交表单等,直接使用axios会导致代码冗余,跨域问题也会影响开发效率,因此封装axios和配置跨域是工程化的关键一步,适用于所有需要接口联调的Vue3项目。
1. 核心知识点
- axios封装:统一配置baseURL、请求超时时间,通过请求/响应拦截器统一处理token、错误提示;
- 跨域解决:开发环境用Vite配置proxy代理,生产环境由后端配置CORS;
- 拦截器作用:请求拦截器添加token、统一请求头;响应拦截器统一处理错误、解析数据。
2. 项目实战代码
(1)axios封装
// api/request.js
import axios from 'axios';
import { ElMessage } from 'element-plus';
import router from '@/router';
// 创建axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL, // 环境变量(区分开发/生产环境)
timeout: 5000, // 超时时间
headers: {
'Content-Type': 'application/json'
}
});
// 请求拦截器:添加token
service.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
// 给所有请求添加Authorization请求头
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
ElMessage.error('请求发起失败,请重试');
return Promise.reject(error);
}
);
// 响应拦截器:统一处理错误、解析数据
service.interceptors.response.use(
(response) => {
// 只返回响应体中的data部分,简化使用
return response.data;
},
(error) => {
// 统一错误提示
const msg = error.response?.data?.msg || '请求失败,请稍后重试';
ElMessage.error(msg);
// 401未授权:token过期或未登录,跳登录页并清除状态
if (error.response?.status === 401) {
localStorage.removeItem('token');
router.push('/login');
}
return Promise.reject(error);
}
);
export default service;
(2)接口统一管理
将所有接口集中管理,便于维护,通用项目代码如下:
// api/list.js(列表相关接口)
import service from './request';
// 获取列表数据
export const getListData = (params) => {
return service({
method: 'GET',
url: '/api/list',
params // 分页、查询条件等参数
});
};
// 上传文件
export const uploadFile = (data) => {
return service({
method: 'POST',
url: '/api/upload',
data,
headers: {
'Content-Type': 'multipart/form-data' // 文件上传需设置
}
});
};
// 组件中使用接口
import { getListData } from '@/api/list';
const getList = async () => {
const res = await getListData({ page: 1, size: 10 });
tableData.value = res.list;
};
(3)Vite配置跨域代理(开发环境)
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src') // 路径别名,@指向src
}
},
// 跨域代理配置
server: {
proxy: {
'/api': {
target: 'http://localhost:3000', // 后端接口地址
changeOrigin: true, // 开启跨域
rewrite: (path) => path.replace(/^/api/, '') // 去掉/api前缀
}
}
}
});
3. 项目实战场景与面试点
- 实战场景:所有接口请求统一使用封装后的axios,无需重复配置baseURL和token;开发环境通过代理解决跨域,顺利联调后端接口;文件上传、接口错误统一处理,提升开发效率,适用于各类需要接口联调的Vue3项目。
- 面试高频问法:① 为什么要封装axios?② Vue项目中遇到跨域怎么解决?③ axios拦截器的作用是什么?
- 面试答案:封装axios可以统一配置、减少重复代码、统一处理错误和token;跨域开发环境用proxy代理,生产环境后端配置CORS;请求拦截器添加token和请求头,响应拦截器统一处理错误、解析数据,避免每个请求都写重复逻辑。
四、Vue3 项目梳理:从功能到面试亮点
这5天的学习,核心是将Vue3的路由、状态管理、工程化能力落地到实战项目中,同时我也重新梳理了自己的Vue3项目,为后续实习面试做准备,整理了通用项目的核心亮点和难点解决方案,供大家参考。
1. 项目核心信息(面试必背)
- 项目名称:Vue3 中后台实战项目
- 技术栈:Vue3 + Vite + Pinia + Element Plus + axios + ECharts
- 核心功能:用户登录、列表展示、详情查看、文件上传、数据查询、数据统计
2. 项目难点与解决方案(面试核心素材)
- 难点1:跨域问题 → 解决方案:Vite配置proxy代理,生产环境后端配置CORS;
- 难点2:用户状态共享 → 解决方案:用Pinia管理全局状态,结合localStorage实现持久化;
- 难点3:接口请求冗余、错误处理繁琐 → 解决方案:封装axios,使用请求/响应拦截器统一处理;
- 难点4:首屏加载慢 → 解决方案:路由懒加载,减小首屏打包体积。
3. 面试可突出的亮点
- 工程化思维:封装axios、统一接口管理,规范项目结构,提升代码可维护性;
- 问题解决能力:遇到跨域、状态管理等问题,能快速找到解决方案并落地;
- 框架熟练度:熟练使用Vue3、Pinia、Vue Router等核心技术,贴合企业开发需求。
总结
这段学习,让我深刻体会到:Vue3框架的核心能力,最终都是为了“高效开发、规范项目、提升体验”。路由控制页面导航,Pinia管理全局状态,axios封装简化接口请求,这些技能不仅能让项目更规范,更是前端实习面试的“硬通货”。
作为大三前端学习者,我明白“实战是最好的老师”,把这些知识点落地到自己的Vue3实战项目中,不仅巩固了基础,也积累了宝贵的面试素材。后续我会继续学习Vue3性能优化、TypeScript等加分项,持续输出实战总结,为实习面试做好充分准备,也希望能帮到和我一样正在努力的前端新手。
后续会持续更新Vue3性能优化、项目踩坑、前端面试题相关内容,欢迎关注~