vue3+ts使用element-plus搭建一个侧边导航菜单,右侧菜单区域视图
时间: 2025-07-19 18:34:08 浏览: 3
<think>根据用户的问题,用户希望使用Vue3、TypeScript和Element Plus实现一个带有侧边导航菜单和右侧内容区域的布局。这是一个典型的后台管理系统布局,通常包含侧边栏(菜单)、顶部导航栏(Header)和主内容区域(Main)。
我将参考Element Plus的官方文档和常见的布局模式,提供以下步骤:
1. 安装Element Plus及其图标库
2. 创建布局组件:Layout(包含侧边栏、头部、主内容区域)
3. 使用Element Plus的Container布局容器(el-container, el-aside, el-header, el-main)
4. 实现侧边栏菜单(使用el-menu组件)
5. 实现路由切换,使右侧内容区域根据路由变化
注意:由于用户使用TypeScript,我们需要为组件添加类型声明。
下面是具体实现:
### 1. 安装Element Plus
如果尚未安装,请先安装Element Plus和它的图标库:
```bash
npm install element-plus @element-plus/icons-vue
```
### 2. 在main.ts中引入Element Plus
```typescript
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
```
### 3. 创建布局组件
在src目录下创建layout文件夹,然后创建以下组件:
- Layout.vue(布局容器)
- Sidebar.vue(侧边栏)
- Header.vue(顶部导航栏)
- Main.vue(主内容区域,这里我们直接使用路由视图)
#### Layout.vue
```vue
<template>
<el-container class="layout-container">
<!-- 侧边栏 -->
<el-aside :width="sidebarWidth">
<Sidebar :collapse="isCollapse" />
</el-aside>
<el-container>
<!-- 头部 -->
<el-header>
<Header @toggle-collapse="toggleCollapse" :collapse="isCollapse" />
</el-header>
<!-- 主内容区域 -->
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import Sidebar from './Sidebar.vue'
import Header from './Header.vue'
const isCollapse = ref(false)
const toggleCollapse = () => {
isCollapse.value = !isCollapse.value
}
// 根据折叠状态设置侧边栏宽度
const sidebarWidth = computed(() => isCollapse.value ? '64px' : '200px')
</script>
<style scoped>
.layout-container {
height: 100vh;
}
.el-header {
background-color: #fff;
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
}
.el-aside {
background-color: #304156;
transition: width 0.3s;
}
.el-main {
padding: 20px;
}
</style>
```
#### Sidebar.vue
```vue
<template>
<el-menu
:default-active="activeMenu"
class="el-menu-vertical"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
:collapse="collapse"
router
>
<el-sub-menu index="1">
<template #title>
<el-icon><location /></el-icon>
<span>导航一</span>
</template>
<el-menu-item index="/dashboard">首页</el-menu-item>
<el-menu-item index="/table">表格</el-menu-item>
</el-sub-menu>
<el-menu-item index="2">
<el-icon><icon-menu /></el-icon>
<span>导航二</span>
</el-menu-item>
</el-menu>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { Location, Menu as IconMenu } from '@element-plus/icons-vue'
defineProps<{
collapse: boolean
}>()
const route = useRoute()
const activeMenu = computed(() => route.path)
</script>
<style>
.el-menu-vertical:not(.el-menu--collapse) {
width: 200px;
}
</style>
```
#### Header.vue
```vue
<template>
<div class="header">
<el-icon @click="toggleCollapse" style="cursor: pointer;">
<Expand v-if="collapse" />
<Fold v-else />
</el-icon>
<!-- 其他头部内容,如面包屑、用户信息等 -->
</div>
</template>
<script setup lang="ts">
import { Expand, Fold } from '@element-plus/icons-vue'
defineProps<{
collapse: boolean
}>()
const emit = defineEmits(['toggle-collapse'])
const toggleCollapse = () => {
emit('toggle-collapse')
}
</script>
<style scoped>
.header {
display: flex;
align-items: center;
}
</style>
```
### 4. 配置路由
在router/index.ts中配置路由,确保路由与菜单的index匹配。例如:
```typescript
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: () => import('@/views/Dashboard.vue'),
meta: { title: '首页' }
},
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { title: '首页' }
},
{
path: '/table',
name: 'Table',
component: () => import('@/views/Table.vue'),
meta: { title: '表格' }
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
```
### 5. 在App.vue中使用布局组件
```vue
<template>
<Layout />
</template>
<script setup lang="ts">
import Layout from '@/layout/Layout.vue'
</script>
```
这样,一个基本的侧边栏导航和右侧视图布局就完成了。用户可以通过点击侧边栏的菜单项来切换右侧内容区域显示的路由组件。
### 注意事项
1. 侧边栏的折叠状态通过一个响应式变量`isCollapse`控制,点击头部菜单的折叠按钮时切换。
2. 侧边栏菜单的`router`属性设置为true,这样菜单项的index值会被当作路由路径进行跳转。
3. 使用`<router-view>`来显示路由对应的组件。
### 优化点
- 可以根据实际需求调整样式
- 侧边栏菜单项可以通过路由配置动态生成
- 添加权限控制,根据用户权限动态生成菜单
希望这个实现能够满足你的需求。如果有任何问题,请随时提问。
§§相关问题§§
1. 如何在Vue3+TypeScript项目中动态生成侧边栏菜单?
2. 如何实现Element Plus侧边栏菜单的权限控制?
3. 在Vue3中,如何优化大型项目的路由配置?</think>以下是一个使用 Vue 3、TypeScript 和 Element Plus 实现侧边栏导航和右侧视图布局的完整方案:
### 1. 安装依赖
```bash
npm install element-plus @element-plus/icons-vue
npm install vue-router@4
```
### 2. 项目结构
```
src/
├── layout/
│ ├── Layout.vue # 主布局组件
│ ├── Sidebar.vue # 侧边栏组件
│ └── Header.vue # 顶部导航栏组件
├── views/ # 页面视图组件
├── router/ # 路由配置
│ └── index.ts
└── App.vue
```
### 3. 路由配置 (`router/index.ts`)
```typescript
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('@/layout/Layout.vue'),
children: [
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue')
},
{
path: '/user',
name: 'User',
component: () => import('@/views/User.vue')
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
```
### 4. 主布局组件 (`layout/Layout.vue`)
```vue
<template>
<el-container class="h-screen">
<!-- 侧边栏 -->
<el-aside :width="sidebarWidth">
<Sidebar :collapse="isCollapse" />
</el-aside>
<el-container>
<!-- 顶部导航栏 -->
<el-header height="50px">
<Header @toggle-collapse="toggleCollapse" :collapse="isCollapse" />
</el-header>
<!-- 主内容区 -->
<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import Sidebar from './Sidebar.vue'
import Header from './Header.vue'
const isCollapse = ref(false)
const toggleCollapse = () => {
isCollapse.value = !isCollapse.value
}
const sidebarWidth = computed(() => isCollapse.value ? '64px' : '200px')
</script>
<style scoped>
.el-header {
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
}
.el-aside {
background-color: #304156;
transition: width 0.3s;
}
</style>
```
### 5. 侧边栏组件 (`layout/Sidebar.vue`)
```vue
<template>
<el-menu
:default-active="activeMenu"
class="el-menu-vertical"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
:collapse="collapse"
router
>
<el-sub-menu index="1">
<template #title>
<el-icon><location /></el-icon>
<span>导航一</span>
</template>
<el-menu-item index="/dashboard">仪表盘</el-menu-item>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><user /></el-icon>
<span>用户管理</span>
</template>
<el-menu-item index="/user">用户列表</el-menu-item>
</el-sub-menu>
</el-menu>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { Location, User } from '@element-plus/icons-vue'
defineProps<{
collapse: boolean
}>()
const route = useRoute()
const activeMenu = computed(() => route.path)
</script>
<style>
.el-menu-vertical:not(.el-menu--collapse) {
width: 200px;
}
</style>
```
### 6. 顶部导航栏组件 (`layout/Header.vue`)
```vue
<template>
<div class="header">
<el-icon @click="toggleCollapse" class="collapse-icon">
<Expand v-if="collapse" />
<Fold v-else />
</el-icon>
<div class="header-right">
<el-dropdown>
<span class="user-info">
<el-avatar size="small" />
<span>管理员</span>
</span>
</el-dropdown>
</div>
</div>
</template>
<script setup lang="ts">
import { Expand, Fold } from '@element-plus/icons-vue'
defineProps<{
collapse: boolean
}>()
const emit = defineEmits(['toggle-collapse'])
const toggleCollapse = () => {
emit('toggle-collapse')
}
</script>
<style scoped>
.header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.collapse-icon {
font-size: 20px;
cursor: pointer;
}
.user-info {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
</style>
```
### 7. 视图组件示例 (`views/Dashboard.vue`)
```vue
<template>
<div class="dashboard">
<h1>仪表盘</h1>
<el-card>
<p>欢迎使用管理系统</p>
</el-card>
</div>
</template>
<script setup lang="ts">
// 业务逻辑代码
</script>
```
### 8. 在 `main.ts` 中全局引入
```typescript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App)
// 注册所有Element图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(router)
app.use(ElementPlus)
app.mount('#app')
```
### 关键功能说明
1. **响应式折叠**:
- 点击顶部导航栏的折叠图标可切换侧边栏宽度
- 使用 `computed` 属性动态计算宽度:`$sidebarWidth = isCollapse ? '64px' : '200px'`
2. **路由集成**:
- 侧边栏菜单的 `router` 属性自动处理导航
- `activeMenu` 根据当前路由高亮菜单项
3. **布局结构**:
```mermaid
graph TD
A[el-container] --> B[el-aside 侧边栏]
A --> C[el-container]
C --> D[el-header 顶部栏]
C --> E[el-main 主内容区]
```
4. **样式优化**:
- 使用 `height: 100vh` 确保全屏高度
- 添加过渡动画使折叠更平滑
- 深色侧边栏搭配浅色内容区
这个布局实现了典型的后台管理系统结构,侧边栏导航包含可折叠菜单,右侧内容区域根据路由动态加载组件[^3][^4]。
阅读全文