一、基本概念






二、运行效果及部分代码
1、运行效果

2、代码目录

3、部分代码
APP.VUE
<script setup>
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
<router-view></router-view>
</template>
Home.vue
<template>
<div class="home-wrap">
<!--头部-->
<MyHeader></MyHeader>
<div class="main-content">
<!--侧边栏-->
<MyAside></MyAside>
<!--内容区域-->
<div class="page-main">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script setup>
import MyHeader from './subcomponents/MyHeader.vue'
import MyAside from './subcomponents/MyAside.vue'
</script>
<style scoped lang="less">
.home-wrap {
height: 100vh;
display: flex;
flex-direction: column;
}
.main-content {
flex:1;
display:flex;
.page-main {
flex:1;
padding:15px;
background:#f6f6f6;
}
}
</style>
MyHeader.vue
<template>
<div class="layout-header-container">
<div class="layout-header-left">
<img src="../../assets/logo.png" class="logo-img" alt="">
<h4>商城后台管理系统</h4>
</div>
<div class="layout-header-right">
<button @click="onLogout">退出</button>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const onLogout = () => {
localStorage.removeItem('token')
router.push('/login')
}
</script>
<style scoped lang="less">
.layout-header-container {
height:60px;
background:#409eff;
display:flex;
justify-content:space-between;
align-items:center;
padding:0 20px;
color:#fff;
.layout-header-left {
display:flex;
align-items:center;
gap:10px;
.logo-img {
width:36px;
}
}
button {
padding:5px 12px;
border:none;
border-radius:3px;
cursor:pointer;
}
}
</style>
MyAside.vue
<template>
<div class="layout-aside-container">
<ul class="menu">
<li class="menu-item">
<router-link to="/home/users">用户管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/rights">权限管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/goods">商品管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/orders">订单管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/settings">系统设置</router-link>
</li>
</ul>
</div>
</template>
<script setup>
</script>
<style scoped lang="less">
.layout-aside-container {
width:180px;
background:#304156;
.menu {
padding:0;
margin:0;
list-style:none;
.menu-item {
a {
display:block;
padding:14px 20px;
color:#bfcbd9;
text-decoration:none;
&.router-link-active {
background:#263445;
color:#409eff;
}
}
}
}
}
</style>
router.js 代码
import { createRouter, createWebHashHistory, RouterView } from 'vue-router'
import { h } from 'vue'
const router = createRouter({
history: createWebHashHistory(),
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: {
render() {
// 我这里没有自己的页面,我只是一个 "容器",用来显示我下面的子页面。
return h(RouterView)
}
},
children: [
{ path: '', component: () => import('./components/subcomponents/MyUsers.vue') },
{ path: ':id', component: () => import('./components/user/MyUserDetail.vue'), props: true }
]
},
{
path: 'rights',
component: () => import('./components/subcomponents/MyRights.vue')
},
{
path: 'goods',
component: () => import('./components/subcomponents/MyGoods.vue')
},
{
path: 'orders',
component: () => import('./components/subcomponents/MyOrders.vue')
},
{
path: 'settings',
component: () => import('./components/subcomponents/MySettings.vue')
}
]
}
]
})
// 路由守卫
router.beforeEach((to, from, next) => {
if (to.path === '/login') {
next()
} else {
const token = localStorage.getItem('token')
token ? next() : next('/login')
}
})
export default router
main.js 代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ScopeSlot from './components/ScopeSlot.vue'
// 引入element-plus核心样式
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
const app = createApp(App)
app.use(ElementPlus).use(router)
app.mount('#app')