1
5.1
案例——后台管理系统
5.1.1
准备工作
1.
创建项目
打开命令行工具,切换到
D:\vue\chapter05
目录,使用
npm
包管理工具创建一个名称
为
manage-system
的项目,具体命令如下。
npm create vite@4.1.0 manage-system -- --template vue
上述命令中,
manage-system
表示项目名称。
在命令行工具中,切换到
manage-system
目录,启动项目。
cd manage-system
npm install
npm run dev
项目启动后,会默认开启一个本地服务
http://127.0.0.1:5173/
。
2.
安装
Vue Router 4
在
manage-system
目录下,安装
Vue Router 4
,具体命令如下。
yarn add vue-router@4 --save
安装成功后,在
src
目录下,新建
router.js
文件,具体代码如下。
1 import { createRouter, createWebHashHistory } from "vue-router";
2 const router = createRouter({
3 history: createWebHashHistory(),
4 routes: []
5 })
6 export default router
在
src\main.js
文件中,导入并挂载路由模块,具体代码如下。
1 import { createApp } from 'vue'
2 import './style.css'
3 import App from './App.vue'
4 import router from './router'
5 const app = createApp(App)
6 app.use(router)
7 app.mount('#app')
3.
安装
Less
依赖包
在
manage-system
目录下,安装
Less
依赖包,具体命令如下。
2
yarn add --save-dev less-loader less
5.1.2
渲染登录组件
在
src/components
目录下创建
Login.vue
组件,然后在
router.js
中导入
Login.vue
组件,
并声明路由规则,最后在
App.vue
组件中声明路由视图。
导入
Login.vue
组件,并声明对应的路由规则,具体代码如下。
routes: [
{ path: '/', redirect:'/login' },
{ path: '/login', component: ()=> import ('./components/Login.vue') },
]
在
App.vue
组件中声明路由视图,清空
App.vue
的默认内容,并编写如下代码。
1 <template>
2 <div id="app">
3 <router-view></router-view>
4 </div>
5 </template>
6 <script>
7
8 </script>
在上述代码中,第
3
行代码声明路由视图。
5.1.3
实现登录功能
用户第一次登录时,前端需要调用后端的接口,并将用户名和密码传给后端,后端收
到请求后,验证用户名和密码,如果验证成功,则返回给前端一个
token
值,前端收到后
端传给的
token
值后,将
token
存储到本地
localStorage
中,前端每次路由跳转,只需判断
localStorage
中是否存在
token
,如果没有则跳转到登录页面,如果存在则跳转到后台页面。
在
src/components
目录下创建
Login.vue
组件,模拟并实现登录功能,具体实现步骤
如下。
① 显示用户头像,引入
assets
目录下的
logo.png
图片,具体代码如下。
1 <template>
2 <div class="login-container">
3 <div class="login-box">
4 <!--
头像区域
-->
5 <div class="avatar-box">
3
6 <img class="avatar" src="../assets/logo.png" />
7 </div>
8 <!--
表单区域
-->
9 <div class="form-login">
10 </div>
11 </div>
12 </div>
13 </template>
14 <script>
15
16 </script>
上述代码中,第
6
行代码使用
<img>
标签引入
logo.png
图片。
② 编写表单区域内容,为登录名称和登录密码的文本框进行双向数据绑定,具体代
码如下。
1 <!--
表单区域
-->
2 <div class="form-login">
3 <!--
登录名称
-->
4 <div class="form-group">
5 <label for="username">
登录名称:
</label>
6 <input
7 type="text"
8 class="form-control"
9 id="username"
10 placeholder="
请输入登录名称
"
11 autocomplete="off"
12 v-model.trim="username"
13 />
14 </div>
15 <!--
登录密码
-->
16 <div class="form-group">
17 <label for="password">
登录密码:
</label>
18 <input
19 type="password"
20 class="form-control"
21 id="password"
22 placeholder="
请输入登录密码
"
23 v-model="password"
24 />
4
25 </div>
26 <!--
登录按钮
-->
27 <div class="form-group">
28 <button type="button" class="btn">
登录
</button>
29 </div>
30 </div>
上述代码中,第
12
行代码通过
v-model
指令绑定
username
,第
23
行代码通过
v-model
指令绑定
password
。
③ 声明
username
和
password
数据,具体代码如下。
1 <script setup>
2 import { ref } from 'vue'
3 const username = ref('')
4 const password = ref('')
5 </script>
④ 为登录按钮绑定单击事件处理函数,具体代码如下。
1 <!--
登录按钮
-->
2 <div class="form-group">
3 <button type="button" class="btn" @click="onLogin">
登录
</button>
4 </div>
上述代码中,为登录按钮绑定
onLogin
事件处理函数。
⑤ 声明
onLogin
事件处理函数,具体代码如下。
1 <script setup>
2
……(原有代码)
3 import { useRouter } from 'vue-router'
4 const router = useRouter()
5
……(原有代码)
6 const onLogin = () => {
7 if (username.value === 'admin' && password.value === '123456') {
8 router.push('/home')
9 return localStorage.setItem('token', 'Bearer xxx')
10 } else {
11 alert('
用户名或密码输入错误
')
12 localStorage.removeItem('token')
13 }
14 }
15 </script>
上述代码中,第
7
行代码使用
if
语句进行判断,当
username.value
为
admin
且
password.value
为
123456
时表示登录成功,执行第
8~9
行代码,跳转到后台首页,并保存
5
token
(这里使用的模拟数据,实际项目中需要获取的
token
由后端返回);如果登录失败
则执行第
11~12
行代码,给出错误提示信息,并清除
token
。
5.1.4
渲染后台主页组件
在
src/components
目录下创建
Home.vue
组件,然后在
router.js
中导入
Home.vue
组件,
并声明路由规则,最后在
App.vue
组件中渲染
Login.vue
组件,具体实现步骤如下。
① 导入
Home.vue
组件,并声明对应的路由规则,具体代码如下。
routes: [
{ path: '/', redirect:'/login' },
{ path: '/login', component: ()=> import ('./components/Login.vue') },
{ path: '/home', component: ()=> import ('./components/Home.vue') },
]
② 渲染
Home.vue
组件的基本结构,具体代码如下。
1 <template>
2 <div class="home-container">
3 <!--
头部区域
-->
4 <my-header></my-header>
5 <!--
主体区域
-->
6 <div class="home-main-box">
7 <!--
左侧边栏区域
-->
8 <my-aside></my-aside>
9 <!--
右侧内容主体区域
-->
10 <div class="home-main-body">
11 <!--
路由的视图
-->
12 <router-view></router-view>
13 </div>
14 </div>
15 </div>
16 </template>
17 <script setup>
18 //
头部组件
19 import MyHeader from './subcomponents/MyHeader.vue'
20 //
左侧边导航组件
21 import MyAside from './subcomponents/MyAside.vue'
22 </script>
6
上述代码中,第
19
行代码导入
MyHeader
组件,第
4
行代码在模板中以
<my-header>
标签的形式使用注册的
MyHeader
组件;第
21
行代码导入
MyAside
组件,第
8
行代码在
模板中以
<my-aside>
标签的形式使用注册的
MyAside
组件。第
12
行代码使用
<router-view>
标签声明路由视图。
③ 在
src/components/subcomponents
目录下新建
MyHeader.vue
组件,实现公共头部
效果,具体代码如下。
1 <template>
2 <div class="layout-header-container">
3 <div class="layout-header-left">
4 <img class="layout-header-left-img" src="../../assets/logo.png"
alt="">
5 <h4 class="layout-header-left-title ml-3">
商城后台管理系统
</h4>
6 </div>
7 <div class="layout-header-right">
8 <button type="button" class="btn btn-light" @click="onLogout">
退出
</button>
9 </div>
10 </div>
11 </template>
上述代码中,第
4
行代码使用
<img>
标签引入
logo.png
图片,第
5
行代码定义标题名
称,第
8
行代码为退出按钮绑定
onLogout
事件处理函数。
④ 在
src/components/subcomponents
目录下,新建
MyAside.vue
组件,实现左侧边栏
导航效果,具体代码如下。
1 <template>
2 <div class="layout-aside-container">
3 <ul class="menu">
4 <li class="menu-item">
5 <router-link to="/home/users">
用户管理
</router-link>
6 </li>
7 <li class="menu-item">
8 <router-link to="/home/rights">
权限管理
</router-link>
9 </li>
10 <li class="menu-item">
11 <router-link to="/home/goods">
商品管理
</router-link>
12 </li>
13 <li class="menu-item">
14 <router-link to="/home/orders">
订单管理
</router-link>
15 </li>
7
16 <li class="menu-item">
17 <router-link to="/home/settings">
系统设置
</router-link>
18 </li>
19 </ul>
20 </div>
21 </template>
上述代码中,第
5
、
8
、
11
、
14
、
17
行代码使用
<router-link>
的
to
属性跳转到指定目标
地址。
⑤ 在
src/router.js
文件中导入左侧边导航对应的组件,具体代码如下。
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: () => import ('./components/Login.vue') },
{
path: '/home',
component: () => import ('./components/Home.vue'),
redirect: '/home/users',
children: [
{
path: 'users',
component: () => import ('./components/subcomponents/MyUsers.vue
')
},
{
path: 'rights',
component: () => import ('./components/subcomponents/MyRights.vue
')
},
{
path: 'goods',
component: () => import ('./components/subcomponents/MyGoods.vue
')
},
{
path: 'orders',
component: () => import ('./components/subcomponents/MyOrders.vue
')
},
{
8
path: 'settings',
component: () => import ('./components/subcomponents/MySettings.
vue')
},
{
path: 'menu',
component: () => import ('./components/subcomponents/MyMenu.vue')
}
]
},
]
上述代码中,导入了
MyUsers
、
MyRights
、
MyGoods
、
MyOrders
、
MySettings
和
MyMenu
组件。在路由匹配规则中,在
home
父路由链接中,使用
redirect
属性将后台主页重定向到
MyUsers
组件;使用
children
属性声明
Home
组件下的子路由匹配规则。
5.1.5
实现退出登录功能
用户想要离开后台主页时,处于安全性考虑,需要退出登录状态,此时单击头部区域
右侧的“退出”按钮,退出后台主页。具体实现步骤如下。
① 在
MyHeader.vue
组件,为登录链接绑定单击事件处理函数,具体代码如下。
<div class="layout-header-right">
<button type="button" class="btn btn-light" @click="onLogout">
退 出
</button>
</div>
上述代码中,为“退出”链接绑定
onLogout
事件处理函数。
② 声明
onLogout
事件处理函数,具体代码如下。
1 <script setup>
2 import { useRouter } from 'vue-router'
3 const router = useRouter()
4 const onLogout = () => {
5 localStorage.removeItem('token')
6 router.push('/login')
7 }
8 </script>
上述代码中,第
5
行代码使用
localStorage.removeItem()
方法移除
token
,第
6
行代码
强制跳转到登录页面。
9
5.1.6
全局控制路由的访问权限
当访问后台主页时,使用全局路由导航守卫控制每个路由的访问权限。如果用户访问
的是登录页面,则执行下一个钩子函数并获取
token
值,如果
token
值不存在或为空,则
强制跳转到登录页面;如果
token
值存在,则跳转到后台主页。
在
src/router.js
文件中,注册全局导航守卫,具体代码如下。
1 router.beforeEach((to, from, next) => {
2 if (to.path === '/login') {
3 return next()
4 }
5 const token = localStorage.getItem('token')
6 if (!token) {
7 return next('/login')
8 }
9 next()
10 })
上述代码中,第
2~4
行代码如果进入的目标路由对象为
login
时,则调用
next()
执行下
一个钩子函数;第
5
行代码获取用户信息
token
值;第
6~8
行代码对
token
值进行判断,
如果
token
值不存在,则强制跳转到
login
组件,如果
token
值存在,则调用
next()
执行下
一个钩子函数。
5.1.7
渲染用户管理页面的数据
用户在登录页面输入正确的用户名和密码后,会跳转到后台管理页面。此时,后台管
理页面会默认显示
MyUsers
组件,在右侧内容部分会显示对应的页面效果。
① 在
src/components/subcomponents
目录下新建
MyUsers.vue
组件,循环用户列表的
数据,具体代码如下。
1 <template>
2 <h4 class="text-center">
用户管理
</h4>
3 <!--
用户列表
-->
4 <table border style="width: 100%">
5 <thead>
6 <tr>
7 <th>
编号
</th>
8 <th>
姓名
</th>
9 <th>
等级
</th>
10
10 <th>
操作
</th>
11 </tr>
12 </thead>
13 <tbody>
14 <tr v-for="(item, i) in userlist" :key="item.id">
15 <td>{{ item.id }}</td>
16 <td>{{ item.name }}</td>
17 <td>{{ item.level }}</td>
18 <td>
详情
</td>
19 </tr>
20 </tbody>
21 </table>
22 </template>
上述代码中,第
14~19
行代码使用
v-for
指令循环渲染
userlist
数组中的数据,绑定
key
属性的属性值是
userlist
数组对象中的
id
属性。
② 定义
userlist
数组,具体代码如下。
1 <script setup>
2 const userlist = [
3 { id: '1', name: '
小明
', level: '
一级客户
' },
4 { id: '2', name: '
小红
', level: '
二级客户
' },
5 { id: '3', name: '
小兰
', level: '
三级客户
' },
6 { id: '4', name: '
小芳
', level: '
四级客户
' }
7 ]
8 </script>
上述代码中,第
2~7
行代码定义
userlist
数组对象,该数组对象中包括
id
、
name
和
level
属性,其中
id
表示用户编号,
name
表示用户名称,
level
表示用户等级。
5.1.8
实现跳转到用户详情页的功能
在用户管理页面单击“详情”链接,跳转到用户详情页面,并传递用户编号值,具体
实现步骤如下。
① 在
MyUser.vue
组件中,渲染详情页的路由链接,具体代码如下。
<td>
<router-link :to="'/home/users/' + item.id">
详情
</router-link>
</td>
在上述代码中,
<router-link>
中的
to
属性表示要跳转的路由规则,传递的参数值为数
组对象中的
id
属性。
11
② 首 先 在
src/components
目 录 下 新 建
user
文 件 夹 , 用 于 存 放 用 户 详 情 页
(
MyUserDetail.vue
)组件;然后在
src/router.js
文件中导入
MyUserDetail.vue
组件;最后
在路由匹配规则中,新建
UserDetail
路由,具体代码如下。
routes: [
{ path: '/', redirect:'/login' },
{ path: '/login', component: ()=> import ('./components/Login.vue') },
{
path: '/home',
component: ()=> import ('./components/Home.vue'),
redirect:'/home/users',
children: [
……(原有代码)
{
path: 'users/:id',
component: ()=> import ('./components/user/MyUserDetail.vue')
}
]
},
]
在上述代码中,在
children
属性中声明路由详情页的路由规则,使用
:
号声明动态参数
名称为
id
,对应的组件名称为
UserDetail
。
5.1.9
使用
props
获取用户编号值
当用户单击“详情”链接时,仅实现了跳转到用户详情页面的功能,此时,在用户详
情页面还不能获取到传递的用户编号值,下面选择使用
props
获取用户编号值。
① 在路由匹配规则中,为用户详情页的路由规则开启
props
传参,具体代码如下。
{
path: 'users/:id',
component: ()=> import ('./components/user/MyUserDetail.vue'), props:
true
}
② 在
MyUserDetail.vue
组件,使用
props
接收路由规则中匹配到的参数项,具体代码
如下。
1 <script setup>
2 const props = defineProps({
3 id: String
12
4 })
5 </script>
上述代码中,第
2~4
行代码接收路由规则中匹配到的参数项
id
。
③ 在
MyUserDetail.vue
组件的模板中,直接使用路由参数,具体代码如下。
1 <template>
2 <button>
后退
</button>
3 <h4>
用户
{{ id }}
的详情页面
</h4>
4 </template>
上述代码中,第
3
行代码用于在页面中显示
id
值。
5.1.10
解决详情页左侧菜单激活问题
当进入到详情页后,左侧菜单“用户管理”激活状态消失,应该将“用户管理”菜单
项激活,具体步骤如下。
① 打开
src\router.js
,在文件开头导入
RouterView
和
h
渲染器,具体代码如下。
1 import {
RouterView,
createRouter, createWebHashHistory } from
'vue-router'
2 import { h } from 'vue'
② 修改
routes
数组中的“
users
”路径的路由,添加
component
和
children
,具体代
码如下。
1 {
2 path: 'users',
3 component: { render: () => h(RouterView) },
4 children: [
5 {
6 path: '',
7 component: () => import ('./components/subcomponents/MyUsers.vue')
8 },
9 {
10 path: ':id',
11 name:'details',
12 component: () => import ('./components/user/MyUserDetail.vue'), props:
true
13 }
14 ]
15 },
13
③ 删除原来的“
user/:id
”路由配置,需要删除的代码如下。
1 {
2 path: 'users/:id',
3 component: ()=> import ('./components/user/MyUserDetail.vue'), props:
true
4 }
④ 访问测试,观察进入用户详情页后,左侧菜单中的“用户管理”是否已被激活
5.1.11
实现后退功能
用户成功跳转到详情页面时,如果想退出当前详情页,则可以单击“后退”按钮,具
体实现步骤如下。
① 在
MyUserDetail.vue
组件,为后退按钮绑定单击事件处理函数,具体代码如下。
<button @click="goBack">
后退
</button>
上述代码中,为“后退”按钮绑定
goBack
事件处理函数
② 在
methods
中声明
goBack
事件处理函数,具体代码如下。
<script setup>
import { useRouter } from 'vue-router'
const props = defineProps({
id: String
})
const router = useRouter()
const goBack = () => {
router.back()
}
</script>
上述代码中,使用
router.back()
后退到上一个组件页面。