侧边栏
大约 4 分钟
下面是一个完整的 Vue 3 管理系统项目,包括项目结构、代码文件和如何运行的命令,帮助你完整地学习如何使用 Vue 3、Pinia、Vue Router 和 Element Plus 来构建一个项目。
点击展开项目代码
完整项目结构
vue3-admin-project/
├── public/
│ └── favicon.ico
├── src/
│ ├── assets/
│ │ └── logo.png
│ ├── components/
│ │ ├── Sidebar.vue
│ │ └── Header.vue
│ ├── views/
│ │ ├── Home.vue
│ │ ├── TableOption1.vue
│ │ ├── TableOption2.vue
│ │ ├── MapComponents.vue
│ │ └── ChartComponents.vue
│ ├── router/
│ │ └── index.ts
│ ├── store/
│ │ └── mainStore.ts
│ ├── App.vue
│ └── main.ts
├── .gitignore
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
代码文件
1. src/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount('#app')
2. src/App.vue
<template>
<el-container class="layout-container">
<el-aside width="200px">
<Sidebar />
</el-aside>
<el-container>
<el-header>
<Header />
</el-header>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script lang="ts" setup>
import Sidebar from './components/Sidebar.vue'
import Header from './components/Header.vue'
</script>
<style scoped>
.layout-container {
height: 100vh;
}
</style>
3. src/components/Sidebar.vue
<template>
<el-menu
default-active="2"
class="el-menu-vertical-demo"
:collapse="isCollapse"
@open="handleOpen"
@close="handleClose"
>
<el-sub-menu index="1">
<template #title>
<el-icon><location /></el-icon>
<span>表格组件</span>
</template>
<el-menu-item-group>
<el-menu-item index="1-1">
<router-link to="/table/option1">选项1</router-link>
</el-menu-item>
<el-menu-item index="1-2">
<router-link to="/table/option2">选项2</router-link>
</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-menu-item index="2">
<el-icon><icon-menu /></el-icon>
<router-link to="/map">
<span>地图组件</span>
</router-link>
</el-menu-item>
<el-menu-item index="3">
<el-icon><document /></el-icon>
<router-link to="/chart">
<span>chart组件</span>
</router-link>
</el-menu-item>
<el-menu-item index="4">
<el-icon><setting /></el-icon>
<router-link to="/">其他组件</router-link>
</el-menu-item>
</el-menu>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { Location, Document, Menu as IconMenu, Setting } from '@element-plus/icons-vue'
const isCollapse = ref(false)
const handleOpen = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
</script>
4. src/components/Header.vue
<template>
<div class="header-container">
<div class="logo">XXX 管理系统</div>
<div class="header-right">
<el-button icon="Expand" @click="toggleFullScreen">全屏</el-button>
<el-badge :value="5" class="item">
<el-button icon="Bell">通知</el-button>
</el-badge>
<el-avatar :size="32" :src="avatarUrl"></el-avatar>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { Expand, Bell } from '@element-plus/icons-vue'
const avatarUrl = ref('https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png')
const toggleFullScreen = () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen()
} else {
if (document.exitFullscreen) {
document.exitFullscreen()
}
}
}
</script>
<style scoped>
.header-container {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
</style>
5. src/views/Home.vue
<template>
<div class="home-container">
<h1>欢迎来到管理系统</h1>
<p>这是一个基于 Vue 3、Pinia 和 Element Plus 的简单后台管理系统。</p>
<p>您可以通过左侧的菜单导航到不同的页面。</p>
<ul>
<li>表格组件</li>
<li>地图组件</li>
<li>图表组件</li>
</ul>
</div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
.home-container {
padding: 20px;
}
</style>
6. src/views/TableOption1.vue
<template>
<div class="table-option1-container">
<h1>选项1 - 表格组件</h1>
<p>这是表格组件的选项1页面。</p>
</div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
.table-option1-container {
padding: 20px;
}
</style>
7. src/views/TableOption2.vue
<template>
<div class="table-option2-container">
<h1>选项2 - 表格组件</h1>
<p>这是表格组件的选项2页面。</p>
</div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
.table-option2-container {
padding: 20px;
}
</style>
8. src/views/MapComponents.vue
<template>
<div class="map-container">
<h1>地图组件</h1>
<p>这是一个简单的地图展示页面,可以集成第三方地图库。</p>
<el-image src="https://webstatic.amap.com/theme/v1.3/images/new_pc/steps/pic3.png" alt="地图示例" />
</div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
.map-container {
padding: 20px;
text-align: center;
}
</style>
9. src/views/ChartComponents.vue
<template>
<div class="chart-container">
<h1>图表组件</h1>
<el-card>
<div ref="chart" style="width: 100%; height: 400px;"></div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import * as echarts from 'echarts'
const chart = ref<HTMLDivElement | null>(null)
onMounted(() => {
if (chart.value) {
const myChart = echarts.init(chart.value)
myChart.setOption({
title: {
text: '简单折线图'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'line'
}]
})
}
})
</script>
<style scoped>
.chart-container {
padding: 20px;
}
</style>
10. src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Home from '../views
/Home.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/table/option1',
name: 'TableOption1',
component: () => import('../views/TableOption1.vue') // 选项1的组件
},
{
path: '/table/option2',
name: 'TableOption2',
component: () => import('../views/TableOption2.vue') // 选项2的组件
},
{
path: '/map',
name: 'Map',
component: () => import('../views/MapComponents.vue')
},
{
path: '/chart',
name: 'Chart',
component: () => import('../views/ChartComponents.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
11. src/store/mainStore.ts
(使用 Pinia 组合式 API)
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useMainStore = defineStore('main', () => {
// state
const count = ref(0)
const name = ref('Eduardo')
// getter
const doubleCount = computed(() => count.value * 2)
// actions
const increment = () => {
count.value++
}
return { count, name, doubleCount, increment }
})
12. vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
})
13. tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"skipLibCheck": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
14. tsconfig.node.json
{
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"composite": true,
"module": "commonjs",
"target": "esnext",
"outDir": "./dist"
},
"include": ["src/**/*.ts"]
}
项目运行命令
创建项目
npm create vite@latest vue3-admin-project -- --template vue-ts
进入项目目录
cd vue3-admin-project
安装依赖
npm install
安装额外依赖
npm install vue-router@4 pinia @element-plus/icons-vue element-plus echarts @tsconfig/node20
启动开发服务器
npm run dev
现在你可以通过 http://localhost:5173
访问项目,点击侧边栏中的不同选项时,URL 将变化,并且显示相应的页面内容。
通过这个完整项目,你可以学习如何使用 Vue 3、Pinia、Vue Router 和 Element Plus 搭建一个后台管理系统。