黑马程序员_大事件项目笔记3_首页部分
首页layout架子[element-plus 菜单组件]
①基本架子拆解(菜单组件的使用)
②登录访问拦截
③用户基本信息获取&渲染
④退出功能[element-plus 确认框]
1.首页-layout 架子分析和登录访问拦截
首页layout架子[element-plus 菜单组件]
①基本架子拆解(菜单组件的使用)
②登录访问拦截
架子组件列表:**
el-container
- el-aside 左侧
- el-menu 左侧边栏菜单
- el-container 右侧
- el-header 右侧头部
- el-dropdown
- el-main 右侧主体
- router-view
基本架子的代码
<script setup>
import {
Management,
Promotion,
UserFilled,
User,
Crop,
EditPen,
SwitchButton,
CaretBottom
} from '@element-plus/icons-vue'
import avatar from '@/assets/default.png'
</script>
<template>
<el-container class="layout-container">
<el-aside width="200px">
<div class="el-aside__logo"></div>
<el-menu
active-text-color="#ffd04b"
background-color="#232323"
:default-active="$route.path"
text-color="#fff"
router
>
<el-menu-item index="/article/channel">
<el-icon><Management /></el-icon>
<span>文章分类</span>
</el-menu-item>
<el-menu-item index="/article/manage">
<el-icon><Promotion /></el-icon>
<span>文章管理</span>
</el-menu-item>
<el-sub-menu index="/user">
<template #title>
<el-icon><UserFilled /></el-icon>
<span>个人中心</span>
</template>
<el-menu-item index="/user/profile">
<el-icon><User /></el-icon>
<span>基本资料</span>
</el-menu-item>
<el-menu-item index="/user/avatar">
<el-icon><Crop /></el-icon>
<span>更换头像</span>
</el-menu-item>
<el-menu-item index="/user/password">
<el-icon><EditPen /></el-icon>
<span>重置密码</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-aside>
<el-container>
<el-header>
<div>黑马程序员:<strong>小帅鹏</strong></div>
<el-dropdown placement="bottom-end">
<span class="el-dropdown__box">
<el-avatar :src="avatar" />
<el-icon><CaretBottom /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="profile" :icon="User"
>基本资料</el-dropdown-item
>
<el-dropdown-item command="avatar" :icon="Crop"
>更换头像</el-dropdown-item
>
<el-dropdown-item command="password" :icon="EditPen"
>重置密码</el-dropdown-item
>
<el-dropdown-item command="logout" :icon="SwitchButton"
>退出登录</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-header>
<el-main>
<router-view></router-view>
</el-main>
<el-footer>大事件 ©2023 Created by 黑马程序员</el-footer>
</el-container>
</el-container>
</template>
<style lang="scss" scoped>
.layout-container {
height: 100vh;
.el-aside {
background-color: #232323;
&__logo {
height: 120px;
background: url('@/assets/logo.png') no-repeat center / 120px auto;
}
.el-menu {
border-right: none;
}
}
.el-header {
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
.el-dropdown__box {
display: flex;
align-items: center;
.el-icon {
color: #999;
margin-left: 10px;
}
&:active,
&:focus {
outline: none;
}
}
}
.el-footer {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #666;
}
}
</style>
将以上代码,复制到layout文件中的LayoutContainer.vue文件中
运行结果
layout文件夹中的LayoutContainer.vue文件
<script setup>
import {
Management,
Promotion,
UserFilled,
User,
Crop,
EditPen,
SwitchButton,
CaretBottom
} from '@element-plus/icons-vue'
import avatar from '@/assets/default.png'
</script>
<template>
<!--
el-menu 整个菜单组件
active-text-color 点击激活
:default-active="$route.path" 配置默认高亮的菜单项
router router选项开启,el-menu-item的index就是点击跳转的路径
el-menu-item菜单项
index="/article/channel" 配置的是访问的跳转路径,配合default-active的值, 实现高亮
-->
<el-container class="layout-container">
<el-aside width="200px">
<div class="el-aside__logo"></div>
<el-menu
active-text-color="#ffd04b"
background-color="#232323"
:default-active="$route.path"
text-color="#fff"
router
>
<el-menu-item index="/article/channel">
<el-icon><Management /></el-icon>
<span>文章分类</span>
</el-menu-item>
<el-menu-item index="/article/manage">
<el-icon><Promotion /></el-icon>
<span>文章管理</span>
</el-menu-item>
<el-sub-menu index="/user">
<!-- 多级菜单的标题 -具名插槽 title -->
<template #title>
<el-icon><UserFilled /></el-icon>
<span>个人中心</span>
</template>
<!-- 展开的内容 -默认插槽 -->
<el-menu-item index="/user/profile">
<el-icon><User /></el-icon>
<span>基本资料</span>
</el-menu-item>
<el-menu-item index="/user/avatar">
<el-icon><Crop /></el-icon>
<span>更换头像</span>
</el-menu-item>
<el-menu-item index="/user/password">
<el-icon><EditPen /></el-icon>
<span>重置密码</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-aside>
<el-container>
<el-header>
<div>黑马程序员:<strong>小帅鹏</strong></div>
<el-dropdown placement="bottom-end">
<span class="el-dropdown__box">
<el-avatar :src="avatar" />
<el-icon><CaretBottom /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="profile" :icon="User"
>基本资料</el-dropdown-item
>
<el-dropdown-item command="avatar" :icon="Crop"
>更换头像</el-dropdown-item
>
<el-dropdown-item command="password" :icon="EditPen"
>重置密码</el-dropdown-item
>
<el-dropdown-item command="logout" :icon="SwitchButton"
>退出登录</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-header>
<el-main>
<router-view></router-view>
</el-main>
<el-footer>大事件 ©2023 Created by 黑马程序员</el-footer>
</el-container>
</el-container>
</template>
<style lang="scss" scoped>
.layout-container {
height: 100vh;
.el-aside {
background-color: #232323;
&__logo {
height: 120px;
background: url('@/assets/logo.png') no-repeat center / 120px auto;
}
.el-menu {
border-right: none;
}
}
.el-header {
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
.el-dropdown__box {
display: flex;
align-items: center;
.el-icon {
color: #999;
margin-left: 10px;
}
&:active,
&:focus {
outline: none;
}
}
}
.el-footer {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #666;
}
}
</style>
vue router官网中的全局前置守卫
下面进行登录访问的拦截
在router文件夹中,index.js文件中的代码
router文件夹中,index.js文件中的所有代码
import { createRouter, createWebHistory } from 'vue-router'
import { useUserStore } from '@/stores'
//createRouter 创建路由实例
//配置history模式
//1.history模式:createWebHistory 地址栏不带 #
//2.hash模式:createWebHashHistory 地址栏带 #
//console.log(import.meta.env.DEV)
//vite中的环境变量 import.meta.env.BASE_URL
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/login', component: () => import('@/views/login/LoginPage.vue') }, //登录页
{
path: '/',
component: () => import('@/views/layout/LayoutContainer.vue'),
redirect: '/article/manage',
children: [
{
path: '/article/manage',
component: () => import('@/views/article/ArticleManage.vue')
},
{
path: '/article/channel',
component: () => import('@/views/article/ArticleChannel.vue')
},
{
path: '/user/profile',
component: () => import('@/views/user/UserProfile.vue')
},
{
path: '/user/avatar',
component: () => import('@/views/user/UserAvatar.vue')
},
{
path: '/user/password',
component: () => import('@/views/user/UserPassword.vue')
}
]
}
]
})
//登录访问拦截=>默认是直接放行的
//根据返回值决定,是放行还是拦截
//返回值:
//1.undefined/true直接放行
//2.false 拦回from的地址页面
//3.具体路径 或 路径对象 拦截到对应的地址
// '/login' {name:'login'}
router.beforeEach((to) => {
//如果没有token,且访问的是非登录页,拦截到登录,其他情况正常放行
const useStore = useUserStore()
if (!useStore.token && to.path !== '/login') return 'login'
return true
})
export default router
2.首页-用户基本信息渲染和退出
③用户基本信息获取&渲染
④退出功能[element-plus 确认框]
先封装一下接口
接口文档链接https://apifox.com/apidoc/shared-26c67aee-0233-4d23-aab7-08448fdf95ff/api-93851860
在api文件夹中的user.js文件中,新建一个方法
//获取用户基本信息
export const userGetInfoService = () => request.get('/my/userinfo')
在stores 文件夹中的 modules文件夹中的user.js文件中
const user = ref({})
const getUser = async () => {
const res = await userGetInfoService() //请求获取数据
user.value = res.data.data
}
return {
token,
setToken,
removeToken,
user,
getUser
}
}
在页面中调用getUser
在页面LayoutContainer.vue文件中
import { useUserStore } from '@/stores'
import { onMounted } from 'vue'
const userStore = useUserStore()
onMounted(() => {
userStore.getUser()
})
做渲染
<div>
黑马程序员:<strong>{{
userStore.user.nickname || userStore.user.username
}}</strong>
</div>
<el-dropdown placement="bottom-end">
<span class="el-dropdown__box">
<el-avatar :src="userStore.user.user_pic || avatar" />
<el-icon><CaretBottom /></el-icon>
</span>
这里的黑马程序员用户名和用户头像已经显示。
el-avatar :src=“userStore.user.user_pic || avatar”
如果该用户有用户头像,及显示该用户头像——>userStore.user.user_pic
如果该用户没有用户头像,及显示一个默认头像——>avatar
// 封装接口的笔记
//api/user.js`封装接口
export const userGetInfoService = () => request.get('/my/userinfo')
userGetInfoService
user是模块名
GetInfo核心的api方法名
Service添加的一个后缀
基本资料,更换头像,重置密码三个下拉菜单是路由跳转
退出登录的功能
Dropdown下拉菜单
路由配置部分——在router文件夹中的index.js文件中
跳转操作的完成
const userStore = useUserStore()
const router = useRouter()
onMounted(() => {
userStore.getUser()
})
const handleCommand = (key) => {
if (key === 'logout') {
//退出操作
} else {
//跳转操作
router.push(`/user/${key}`)
}
}
下拉菜单跳转完成
退出功能
const handleCommand = (key) => {
if (key === 'logout') {
//退出操作
//清除本地的数据(token+user信息)
userStore.removeToken()
userStore.setUser({})
router.push('/login')
} else {
//跳转操作
router.push(`/user/${key}`)
}
}
给点击退出按钮加提示信息
<template>
<el-button text @click="open">Click to open the Message Box</el-button>
</template>
<script lang="ts" setup>
import { ElMessage, ElMessageBox } from 'element-plus'
const open = () => {
ElMessageBox.confirm(
'proxy will permanently delete the file. Continue?',
'Warning',
{
confirmButtonText: 'OK',
cancelButtonText: 'Cancel',
type: 'warning',
}
)
.then(() => {
ElMessage({
type: 'success',
message: 'Delete completed',
})
})
.catch(() => {
ElMessage({
type: 'info',
message: 'Delete canceled',
})
})
}
</script>
确认这里有没有配置ElMessageBox
完成情况
layout文件夹中的LayoutContainer.vue文件中的所有代码
<script setup>
import {
Management,
Promotion,
UserFilled,
User,
Crop,
EditPen,
SwitchButton,
CaretBottom
} from '@element-plus/icons-vue'
import avatar from '@/assets/default.png'
import { useUserStore } from '@/stores'
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'
const userStore = useUserStore()
const router = useRouter()
onMounted(() => {
userStore.getUser()
})
const handleCommand = async (key) => {
if (key === 'logout') {
//退出操作
await ElMessageBox.confirm('你确认要进行退出吗', '温馨提示', {
type: 'warning',
confirmButtonText: '确认',
cancelButtonText: '取消'
})
//清除本地的数据(token+user信息)
userStore.removeToken()
userStore.setUser({})
router.push('/login')
} else {
//跳转操作
router.push(`/user/${key}`)
}
}
</script>
<template>
<!--
el-menu 整个菜单组件
active-text-color 点击激活
:default-active="$route.path" 配置默认高亮的菜单项
router router选项开启,el-menu-item的index就是点击跳转的路径
el-menu-item菜单项
index="/article/channel" 配置的是访问的跳转路径,配合default-active的值, 实现高亮
-->
<el-container class="layout-container">
<el-aside width="200px">
<div class="el-aside__logo"></div>
<el-menu
active-text-color="#ffd04b"
background-color="#232323"
:default-active="$route.path"
text-color="#fff"
router
>
<el-menu-item index="/article/channel">
<el-icon><Management /></el-icon>
<span>文章分类</span>
</el-menu-item>
<el-menu-item index="/article/manage">
<el-icon><Promotion /></el-icon>
<span>文章管理</span>
</el-menu-item>
<el-sub-menu index="/user">
<!-- 多级菜单的标题 -具名插槽 title -->
<template #title>
<el-icon><UserFilled /></el-icon>
<span>个人中心</span>
</template>
<!-- 展开的内容 -默认插槽 -->
<el-menu-item index="/user/profile">
<el-icon><User /></el-icon>
<span>基本资料</span>
</el-menu-item>
<el-menu-item index="/user/avatar">
<el-icon><Crop /></el-icon>
<span>更换头像</span>
</el-menu-item>
<el-menu-item index="/user/password">
<el-icon><EditPen /></el-icon>
<span>重置密码</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-aside>
<el-container>
<el-header>
<div>
黑马程序员:<strong>{{
userStore.user.nickname || userStore.user.username
}}</strong>
</div>
<el-dropdown placement="bottom-end" @command="handleCommand">
<!-- 展示给用户,默认看到的 -->
<span class="el-dropdown__box">
<el-avatar :src="userStore.user.user_pic || avatar" />
<el-icon><CaretBottom /></el-icon>
</span>
<!-- 折叠的下拉部分 -->
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="profile" :icon="User"
>基本资料</el-dropdown-item
>
<el-dropdown-item command="avatar" :icon="Crop"
>更换头像</el-dropdown-item
>
<el-dropdown-item command="password" :icon="EditPen"
>重置密码</el-dropdown-item
>
<el-dropdown-item command="logout" :icon="SwitchButton"
>退出登录</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-header>
<el-main>
<router-view></router-view>
</el-main>
<el-footer>大事件 ©2023 Created by 黑马程序员</el-footer>
</el-container>
</el-container>
</template>
<style lang="scss" scoped>
.layout-container {
height: 100vh;
.el-aside {
background-color: #232323;
&__logo {
height: 120px;
background: url('@/assets/logo.png') no-repeat center / 120px auto;
}
.el-menu {
border-right: none;
}
}
.el-header {
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
.el-dropdown__box {
display: flex;
align-items: center;
.el-icon {
color: #999;
margin-left: 10px;
}
&:active,
&:focus {
outline: none;
}
}
}
.el-footer {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #666;
}
}
</style>
、