前端路由vs后端路由:
后端路由:以前网页跳转: 点击链接 → 浏览器发请求给服务器 服务器找到对应页面文件,返回给浏览器 → 整个页面刷新
缺点:页面全部刷新,卡顿,体验差。
前端路由:页面跳转不向服务器请求新页面,浏览器不整体刷新,只局部切换组件。 整个项目只有一份 index.html,所有页面切换都在浏览器内部由 JS 控制。
然后就是前端路由的两种模式:
hash模式和history模式,

(hash模式刷新不会404的原因是因为#后面的(包括#)不会返回给服务端,这样的话就算找不到相应需要切换的文件也不会报错,相反history模式就直接全部返回给服务端查找,找不到就返回给客户端报错的404)

嵌套路由:
eg

两者都有相同的essentials前缀,可以想象浏览器上的文档,旁边的目录里包括了很多部分,点击的时候就会进行界面的刷新切换,目录就是一个组件(相当于这里的essentials),旁边就是其他的组件(essentials后面的路径)。
@路经,
//@路径别名简化了导入文件的路劲(src/..../components),
import Backendlayout from '@/components/Backendlayout.vue'
这个@只是方便了我们开发时,在导入路径的时候从头写到尾,避免写漏,但是它实际上是空的,需要我们再单独配置
路由配置简单代码实现,注意子路由前面不要/,不然拼接到根目录了而没有和/back拼接,也就没有子界面
import { createRouter, createWebHashHistory } from 'vue-router'
//@路径别名简化了导入文件的路劲(src/..../components),
import Backendlayout from '@/components/Backendlayout.vue'
//路由配置
const routes = [
{
path: '/back',
component: Backendlayout,
//子路由配置也必须是数组
children:[
{
path:'home',
component: () => import('@/views/Home.vue')
}
]
}
]
//创建路由实例
const router=createRouter({
history:createWebHashHistory(),
routes
})
//导出路由实例
export default router
vue3:
定位:前端开发框架 作用:提供语法、响应式、路由、组件系统、生命周期等所有基础能力,用来搭建整个网站。 没有 Vue3,你都没法写.vue 文件、无法使用组件。
类比:房子建造全套施工标准、工具、图纸规范
layout:
定位:页面布局容器(组件) 作用:页面外层通用骨架,一般包含头部、侧边栏、主体内容区、底部。 多个页面共用这层外壳,只更换中间主体内

()登录界面的Axios二次封装和接口的调用,通过请求拦截器自动注入token,通过响应拦截器统一处理状态码 :
首先是对于这里的token理解,由于http协议并不会记住刚才登录的人是你。如果没有任何凭证,后端会一脸懵,也就是说登录并验证通过只是一时的,后续的数据发送还需要通过一个验证来保持你的登录状态,这就是token
token不是固定一个的,而且它是有生命周期的,当token失效的时候 说明你要重新进新登录操作。

这一块的功能主要是前后端交互的数据流,进行从浏览器发请求 -> 到 Vite 代理 -> 到后端 -> 再返回浏览器,这叫一次完整的 HTTP 请求生命周期
首先是login文件里的代码
<template>
<div class="container">
<div class="title">
<div class="back-home">
<el-icon><Back /></el-icon>
<span>返回首页</span>
</div>
<div class="title-text">
<h2>登录您的账户</h2>
<p>请输入您的登录信息</p>
</div>
</div>
<div class="from-container">
<el-form ref="ruleFormRef" :model="formData" :rules="rules" label-position="top">
<el-form-item label="用户名或邮箱" prop="username">
<el-input v-model="formData.username" size="large" placeholder="请输入用户名或邮箱" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="formData.password" size="large" type="password" show-password placeholder="请输入密码" />
</el-form-item>
<el-button class="btn" size="large" type="primary" @click="submitForm(ruleFormRef)">登录</el-button>
</el-form>
<div class="footer">
<p>还没有账户?<router-link to="/auth/register">去注册</router-link></p>
</div>
</div>
</div>
</template>
<script setup>
import {ref,reactive} from'vue'
//引入登录接口
import {login} from '@/api/admin'
const ruleFormRef= ref()
const formData= reactive({
username:'',
password:''
})
const rules= reactive({
username:[
{required: true, message:'请输入用户名',trigger: 'blur'}
],
password:[
{ required: true,message:'请输入密码',trigger:'blur'}
]
})
const submitForm= async(formEl)=>{
if(!formEl) return
//登录校验函数
await formEl.validate((valid, fields)=>{
//校验通过 表示存在 后续调用接口
if(valid){
login(formData).then(data =>{
if(!data.token) {
return console.error('登录失败')
}
//登录成功,保存token和用户信息
localStorage.setItem('token',data.token)
localStorage.setItem('userInfo',JSON.stringify(data.userInfo))
})
}
})
}
这里主要是读取输入框用户的账号和姓名的逻辑,在script里导入
这两个是响应式工具,
这个数组formData负责存储用户的账户和密码
表单验证规则 true表示必须填写,如果不填写就会出现相应的提示,trigger表示失去焦点时触发验证(也就是从输入框点出去的那一刻)
效果:
这里进行数据的接收和发送,login方法我们封装在admin文件中
submitForm是一个异步函数(不会等耗时操作完成,先继续跑后面代码,等耗时任务完成之后,再回来处理结果)
这里是进行表单验证,但是还没写先不管
接着就是先通过valid验证是否都填入 然后往login里面传入数组(formData),发送完 then执行接收后端传来的data数据,并取出数据里的token进行校验,若存在即说明有这个客户就通过

login里的样式:
</script>
<style scoped lang="scss">
.container{
width:384px;
.title{
.back-home{
margin-bottom: 60px;
}
.title-text{
text-align: center;
h2{
font-size: 36px;
margin-bottom: 10px;
}
p{
font-size: 18px;
color:#6b7280;
}
}
}
}
.from-container{
margin-top: 30px;
.btn{
margin-top: 40px;
width: 100%;
}
.footer{
padding: 30px;
text-align:center;
}
}
</style>
接着讲解request文件的逻辑:
import axios from 'axios'
import {ElMessage} from 'element-plus'
//创建axios实例
const service = axios.create({
baseURL: '/api',
//请求超时时间
timeout: 5000,
})
//请求拦截器
service.interceptors.request.use(
config => {
//在发送请求之前做些什么
const token = localStorage.getItem('token')
//如果存在token,就添加到请求头中
if(token){
config.headers['token']= token
}
return config
},
(error) => {
//对请求错误做些什么
return Promise.reject(error)
}
)
//响应拦截器
service.interceptors.response.use(
response => {
//对响应数据做点什么
const{data,config}=response
if(data.code==='200'){
return data.data
}else{
if(data.code==='-1'){
if(!config.url.includes('/login')){
ElMessage.error(data.msg||'登录过期,请重新登录')
//清楚登录信息
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
window.location.href='/auth/login'
router.push('/auth/login')
}
}else{
ElMessage.error(data.msg||'登录过期,请重新登录')
return Promise.reject('网络请求失败....')
}
}
return response
},
(error) => {
//对响应错误做点什么
return Promise.reject(error)
}
)
//暴露axios实例对象
export default service
主题是两个拦截器,请求和响应的,开头我们需要创建axios对象

也就是说没有axios只能停留在javaScript变量层面,数据也发不出收不到。
请求拦截器的触发一般是我们在login传入数组后,service准备在admin里post发送数据,但是发送前会对数据进行配置,首先就是地址

在这个代码里

先获取磁盘中是否有存入token,如果有就直接用,要是有其他错误就直接报错
最后这一句至关重要,他的意思是对所有文件进行暴露,也就是所有文件可以用这个request文件