1. Vue项目搭建入门指南
作为前端开发领域最受欢迎的框架之一,Vue.js以其轻量级和渐进式特性赢得了大量开发者的青睐。我刚接触Vue时也经历过从零开始的摸索阶段,现在就把这些年积累的Vue项目搭建经验整理成这份保姆级教程。不同于官方文档的全面性,这里更侧重实际开发中真正用得到的核心配置和避坑技巧。
Vue项目搭建主要涉及环境准备、脚手架初始化、核心配置调整和基础结构设计四个关键环节。我们将使用Vue CLI作为项目脚手架工具,它不仅提供了标准化的项目模板,还能灵活配置各种现代化前端工具链。对于初学者来说,建议从Vue 2.x版本开始学习,虽然Vue 3已经发布,但当前企业项目中2.x版本仍占较大比例,生态也更成熟稳定。
提示:安装Node.js时建议选择LTS版本(当前为16.x),避免使用最新奇数版本可能存在的兼容性问题。Windows用户记得勾选"Automatically install the necessary tools"选项。
2. 环境准备与工具链配置
2.1 Node.js环境安装与验证
首先需要安装Node.js运行环境,它将提供npm包管理工具。访问Node.js官网下载安装包时,我强烈建议选择Windows Installer (.msi)格式而非.zip压缩包,这样可以自动配置环境变量。安装完成后,在命令行执行以下命令验证安装:
bash复制node -v # 应显示v14.x或更高版本
npm -v # 6.x以上版本
如果遇到权限问题(特别是在Linux/Mac系统),可以按照以下方式解决:
bash复制mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
2.2 Vue CLI脚手架全局安装
Vue CLI是官方提供的标准项目脚手架工具,通过以下命令安装最新稳定版:
bash复制npm install -g @vue/cli
# 安装完成后验证版本
vue --version
国内用户可能会遇到下载速度慢的问题,可以通过以下两种方案解决:
- 使用淘宝镜像源:
bash复制npm install -g cnpm --registry=https://registry.npmmirror.com
cnpm install -g @vue/cli
- 临时切换npm源:
bash复制npm config set registry https://registry.npmmirror.com
npm install -g @vue/cli
npm config set registry https://registry.npmjs.org
2.3 浏览器开发工具准备
建议安装以下浏览器扩展辅助开发:
- Vue Devtools:官方调试工具(Chrome/Firefox扩展)
- React Developer Tools:虽然主要用于React但有时也需查看虚拟DOM
- Redux DevTools:如需使用Vuex状态管理时非常有用
常见问题:Vue Devtools在本地开发服务器(localhost)可能无法自动检测,此时需要手动点击扩展图标或在扩展设置中勾选"允许访问文件URL"。
3. 项目初始化与核心配置
3.1 使用Vue CLI创建项目
在目标目录执行以下命令创建新项目:
bash复制vue create my-vue-project
交互式命令行将提示选择预设配置,初学者建议选择"Default (Vue 2)",有经验的开发者可以选择"Manually select features"进行自定义:
code复制? Please pick a preset:
Default ([Vue 2] babel, eslint)
Default (Vue 3) ([Vue 3] babel, eslint)
Manually select features
手动模式下的功能选项说明:
- Babel:ES6+语法转换(必选)
- TypeScript:如需使用TS开发
- Progressive Web App (PWA) Support:PWA应用支持
- Router:官方路由管理器
- Vuex:状态管理库
- CSS Pre-processors:CSS预处理器(Sass/Less等)
- Linter / Formatter:代码规范检查
- Unit Testing:单元测试
- E2E Testing:端到端测试
3.2 项目目录结构解析
初始化完成后的标准目录结构如下:
code复制my-vue-project/
├── node_modules/ # 依赖模块
├── public/ # 静态资源
│ ├── favicon.ico
│ └── index.html # 主HTML文件
├── src/ # 源代码
│ ├── assets/ # 静态资源
│ ├── components/ # 公共组件
│ ├── App.vue # 根组件
│ └── main.js # 应用入口
├── .gitignore # Git忽略配置
├── babel.config.js # Babel配置
├── package.json # 项目配置
└── README.md # 项目说明
3.3 关键配置文件调整
babel.config.js
默认配置通常无需修改,如需兼容旧浏览器可调整targets:
javascript复制module.exports = {
presets: [
['@vue/cli-plugin-babel/preset', {
targets: {
ie: '11',
chrome: '58'
}
}]
]
}
package.json
重点关注scripts部分:
json复制{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
}
}
可以添加自定义脚本如:
json复制"scripts": {
"analyze": "vue-cli-service build --report"
}
4. 开发服务器与构建优化
4.1 启动开发服务器
执行以下命令启动开发服务器:
bash复制npm run serve
默认会启动在http://localhost:8080/,控制台将显示访问地址。开发服务器支持热重载(HMR),修改代码后会立即更新浏览器视图而无需手动刷新。
实用技巧:如果8080端口被占用,可以通过修改vue.config.js配置指定端口:
javascript复制module.exports = {
devServer: {
port: 3000
}
}
4.2 常用开发配置调整
在vue.config.js中可以自定义webpack配置(无需弹出配置):
javascript复制module.exports = {
// 基本路径
publicPath: process.env.NODE_ENV === 'production' ? '/production-sub-path/' : '/',
// 输出目录
outputDir: 'dist',
// 静态资源目录
assetsDir: 'static',
// 是否启用source map
productionSourceMap: false,
// CSS相关配置
css: {
extract: true, // 生产环境提取CSS
sourceMap: false,
loaderOptions: {
sass: {
prependData: `@import "@/styles/variables.scss";`
}
}
}
}
4.3 生产环境构建优化
执行构建命令生成生产环境代码:
bash复制npm run build
构建优化建议:
- 使用
--modern模式生成现代/传统两套包:
bash复制vue-cli-service build --modern
- 开启gzip压缩(需安装compression-webpack-plugin):
javascript复制const CompressionPlugin = require('compression-webpack-plugin')
module.exports = {
configureWebpack: {
plugins: [
new CompressionPlugin({
test: /\.(js|css)$/,
threshold: 10240
})
]
}
}
- 配置SplitChunks优化分包:
javascript复制module.exports = {
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'all',
maxSize: 244 * 1024 // 244KB
}
}
}
}
5. 核心功能集成与常见问题
5.1 Vue Router集成
安装路由插件:
bash复制vue add router
或手动安装:
bash复制npm install vue-router
基本路由配置示例(src/router/index.js):
javascript复制import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
5.2 Vuex状态管理
安装Vuex:
bash复制vue add vuex
或手动安装:
bash复制npm install vuex
基础store配置(src/store/index.js):
javascript复制import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
},
getters: {
doubleCount: state => state.count * 2
}
})
5.3 常见问题解决方案
-
ESLint报错问题:
- 错误:'defineProps' is not defined
- 解决:在.eslintrc.js中添加:
javascript复制globals: { defineProps: 'readonly', defineEmits: 'readonly' }
-
组件引入路径问题:
- 推荐使用@别名指向src目录:
javascript复制import MyComponent from '@/components/MyComponent.vue'
- 推荐使用@别名指向src目录:
-
热更新失效:
- 检查vue.config.js是否配置了:
javascript复制devServer: { hot: true } - 确保组件有name选项
- 检查vue.config.js是否配置了:
-
生产环境静态资源404:
- 设置正确的publicPath:
javascript复制module.exports = { publicPath: process.env.NODE_ENV === 'production' ? './' : '/' }
- 设置正确的publicPath:
-
跨域问题解决:
配置开发服务器代理:javascript复制module.exports = { devServer: { proxy: { '/api': { target: 'http://your-api-server.com', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }
6. 项目结构与最佳实践
6.1 推荐项目结构
经过多个项目实践,我总结出以下高效的项目结构:
code复制src/
├── api/ # API请求封装
├── assets/ # 静态资源
│ ├── fonts/ # 字体文件
│ ├── images/ # 图片资源
│ └── styles/ # 全局样式
├── components/ # 公共组件
│ ├── common/ # 全局通用组件
│ └── business/ # 业务组件
├── directives/ # 自定义指令
├── filters/ # 全局过滤器
├── mixins/ # 混入对象
├── plugins/ # 插件
├── router/ # 路由配置
├── store/ # Vuex状态管理
│ ├── modules/ # 模块化store
│ └── index.js # 主store文件
├── utils/ # 工具函数
├── views/ # 页面组件
├── App.vue # 根组件
└── main.js # 应用入口
6.2 组件设计规范
-
组件命名:
- 基础组件:前缀
Base(如BaseButton) - 业务组件:前缀
App(如AppProductCard) - 单例组件:前缀
The(如TheHeader)
- 基础组件:前缀
-
组件结构:
vue复制<template> <div class="component-class"> <!-- 组件模板 --> </div> </template> <script> export default { name: 'ComponentName', // 必须 props: {}, // 类型验证 data() { return {} }, computed: {}, methods: {}, created() {}, mounted() {} } </script> <style scoped> /* 组件样式 */ </style> -
Props验证:
javascript复制props: { status: { type: String, required: true, validator: value => { return ['success', 'warning', 'danger'].includes(value) } } }
6.3 性能优化实践
-
组件懒加载:
javascript复制const UserDetails = () => import('./views/UserDetails.vue') -
路由懒加载:
javascript复制{ path: '/settings', component: () => import('@/views/Settings.vue') } -
图片懒加载:
使用vue-lazyload插件:javascript复制import VueLazyload from 'vue-lazyload' Vue.use(VueLazyload, { preLoad: 1.3, error: 'error.png', loading: 'loading.gif', attempt: 1 }) -
虚拟滚动:
对于长列表使用vue-virtual-scroller:vue复制<template> <RecycleScroller class="scroller" :items="items" :item-size="32" key-field="id" v-slot="{ item }" > <div class="user">{{ item.name }}</div> </RecycleScroller> </template>
7. 进阶配置与插件集成
7.1 环境变量配置
在项目根目录创建环境文件:
.env:通用环境变量.env.development:开发环境.env.production:生产环境
变量命名必须以VUE_APP_开头:
code复制VUE_APP_API_URL=https://api.example.com
VUE_APP_DEBUG=true
使用方式:
javascript复制const apiUrl = process.env.VUE_APP_API_URL
7.2 常用插件推荐
-
axios:HTTP客户端
bash复制
npm install axios封装示例:
javascript复制import axios from 'axios' const service = axios.create({ baseURL: process.env.VUE_APP_API_URL, timeout: 10000 }) // 请求拦截 service.interceptors.request.use(config => { config.headers['Authorization'] = getToken() return config }) // 响应拦截 service.interceptors.response.use( response => response.data, error => { return Promise.reject(error) } ) export default service -
Element UI:桌面端组件库
bash复制
npm install element-ui按需引入:
javascript复制import { Button, Select } from 'element-ui' Vue.use(Button) Vue.use(Select) -
Vant:移动端组件库
bash复制
npm install vant按需引入配置:
javascript复制module.exports = { plugins: [ ['import', { libraryName: 'vant', libraryDirectory: 'es', style: true }, 'vant'] ] }
7.3 自定义指令示例
全局注册指令(src/directives/index.js):
javascript复制import Vue from 'vue'
// 权限指令
Vue.directive('permission', {
inserted(el, binding) {
const { value } = binding
const permissions = store.getters.permissions
if (!permissions.includes(value)) {
el.parentNode && el.parentNode.removeChild(el)
}
}
})
// 复制指令
Vue.directive('copy', {
bind(el, { value }) {
el.$value = value
el.handler = () => {
const textarea = document.createElement('textarea')
textarea.value = el.$value
document.body.appendChild(textarea)
textarea.select()
document.execCommand('Copy')
document.body.removeChild(textarea)
}
el.addEventListener('click', el.handler)
},
componentUpdated(el, { value }) {
el.$value = value
},
unbind(el) {
el.removeEventListener('click', el.handler)
}
})
8. 测试与部署
8.1 单元测试配置
Vue CLI已集成Jest测试框架,创建测试文件(如example.spec.js):
javascript复制import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message'
const wrapper = shallowMount(HelloWorld, {
propsData: { msg }
})
expect(wrapper.text()).toMatch(msg)
})
})
运行测试:
bash复制npm run test:unit
8.2 E2E测试配置
使用Cypress进行端到端测试:
bash复制vue add @vue/e2e-cypress
示例测试文件(tests/e2e/specs/test.js):
javascript复制describe('My First Test', () => {
it('Visits the app root url', () => {
cy.visit('/')
cy.contains('h1', 'Welcome to Your Vue.js App')
})
})
运行测试:
bash复制npm run test:e2e
8.3 部署到Nginx
构建生产包:
bash复制npm run build
Nginx配置示例:
nginx复制server {
listen 80;
server_name yourdomain.com;
location / {
root /path/to/your/project/dist;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://api-server;
proxy_set_header Host $host;
}
}
8.4 Docker部署
创建Dockerfile:
dockerfile复制# 构建阶段
FROM node:14 as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
构建并运行:
bash复制docker build -t vue-app .
docker run -d -p 8080:80 --name my-vue-app vue-app
9. 项目升级与维护
9.1 Vue 2升级Vue 3
官方提供了迁移构建版本,可以逐步升级:
- 安装兼容版本:
bash复制npm install vue@^2.7
npm install @vue/compat
- 配置兼容模式(vue.config.js):
javascript复制module.exports = {
chainWebpack: config => {
config.resolve.alias.set('vue', '@vue/compat')
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
return {
...options,
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
})
}
}
9.2 依赖更新策略
- 使用npm-check-updates检查更新:
bash复制npx npm-check-updates
- 安全更新命令:
bash复制npm update
- 大版本更新建议:
- 先更新开发依赖(如webpack、babel相关)
- 再更新Vue生态相关(vue-router、vuex等)
- 最后更新Vue核心版本
- 每次更新后运行测试用例
9.3 长期维护建议
-
版本锁定策略:
- 精确版本:
1.2.3 - 兼容版本:
^1.2.3(允许小版本和补丁更新) - 开发依赖使用
^ - 生产依赖考虑精确版本
- 精确版本:
-
定期执行:
bash复制npm audit fix
- 维护分支策略:
- master:生产环境代码
- develop:开发分支
- feature/xxx:功能分支
- hotfix/xxx:紧急修复分支
10. 实战技巧与经验分享
10.1 动态主题切换实现
- 定义CSS变量:
css复制:root {
--primary-color: #409EFF;
--success-color: #67C23A;
}
- 创建主题文件(src/styles/themes/dark.scss):
scss复制:root {
--primary-color: #3375b9;
--success-color: #4e8e2f;
}
- 动态加载主题:
javascript复制function loadTheme(themeName) {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = `/styles/themes/${themeName}.css`
link.id = 'theme-style'
const oldLink = document.getElementById('theme-style')
if (oldLink) {
document.head.replaceChild(link, oldLink)
} else {
document.head.appendChild(link)
}
}
10.2 权限控制方案
- 路由权限控制:
javascript复制router.beforeEach((to, from, next) => {
const hasToken = getToken()
if (to.meta.requiresAuth && !hasToken) {
next('/login')
} else if (to.path === '/login' && hasToken) {
next('/')
} else {
next()
}
})
- 按钮级权限:
javascript复制Vue.directive('permission', {
inserted(el, binding) {
const { value } = binding
const permissions = store.getters.permissions
if (!permissions.includes(value)) {
el.parentNode && el.parentNode.removeChild(el)
}
}
})
10.3 错误监控与性能追踪
- 使用Sentry进行错误监控:
bash复制npm install @sentry/vue @sentry/tracing
配置:
javascript复制import * as Sentry from '@sentry/vue'
import { Integrations } from '@sentry/tracing'
Sentry.init({
Vue,
dsn: 'your-dsn',
integrations: [new Integrations.BrowserTracing()],
tracesSampleRate: 0.2
})
- 自定义错误处理:
javascript复制Vue.config.errorHandler = (err, vm, info) => {
console.error(`Error: ${err.toString()}\nInfo: ${info}`)
Sentry.captureException(err)
}
10.4 移动端适配方案
- viewport配置(public/index.html):
html复制<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
- 使用postcss-px-to-viewport插件:
bash复制npm install postcss-px-to-viewport -D
配置(postcss.config.js):
javascript复制module.exports = {
plugins: {
'postcss-px-to-viewport': {
viewportWidth: 375,
unitPrecision: 5,
viewportUnit: 'vw',
selectorBlackList: [],
minPixelValue: 1,
mediaQuery: false
}
}
}
- 1px边框解决方案:
scss复制@mixin thin-border($direction, $color) {
position: relative;
&::after {
content: '';
position: absolute;
#{$direction}: 0;
left: 0;
right: 0;
height: 1px;
background-color: $color;
transform: scaleY(0.5);
transform-origin: $direction center;
}
}
11. 项目优化深度实践
11.1 代码分割与懒加载
- 路由级别分割:
javascript复制const UserProfile = () => import(/* webpackChunkName: "user" */ './views/UserProfile.vue')
- 组件级别分割:
vue复制<script>
const HeavyComponent = () => import('./HeavyComponent.vue')
export default {
components: {
HeavyComponent
}
}
</script>
- Webpack手动分包:
javascript复制module.exports = {
configureWebpack: {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
}
11.2 性能监控与分析
- 使用webpack-bundle-analyzer分析包大小:
bash复制npm install webpack-bundle-analyzer -D
配置:
javascript复制const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
chainWebpack: config => {
config.plugin('analyzer').use(BundleAnalyzerPlugin)
}
}
运行分析:
bash复制npm run build --report
- Lighthouse性能检测:
- 安装Chrome插件
- 或使用命令行工具:
bash复制npm install -g lighthouse
lighthouse http://localhost:8080 --view
11.3 缓存策略优化
- 文件名哈希策略:
javascript复制module.exports = {
filenameHashing: true,
configureWebpack: {
output: {
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].js'
}
}
}
- 长期缓存配置:
javascript复制module.exports = {
chainWebpack: config => {
config.plugin('html').tap(args => {
args[0].minify = {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: false,
minifyCSS: true,
minifyJS: true
}
return args
})
}
}
- Service Worker缓存(PWA):
javascript复制module.exports = {
pwa: {
workboxPluginMode: 'GenerateSW',
workboxOptions: {
skipWaiting: true,
clientsClaim: true,
exclude: [/\.map$/, /_redirects/],
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.example\.com/,
handler: 'NetworkFirst'
}
]
}
}
}
12. 企业级项目架构设计
12.1 模块化架构设计
- 功能模块划分:
code复制src/
├── modules/
│ ├── auth/ # 认证模块
│ │ ├── api.js # API接口
│ │ ├── store.js # Vuex模块
│ │ └── routes.js # 路由配置
│ ├── user/ # 用户模块
│ └── product/ # 产品模块
- 模块注册机制:
javascript复制// src/modules/index.js
const requireModule = require.context('.', true, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
if (fileName === './index.js') return
const moduleName = fileName.replace(/(\.\/|\.js)/g, '')
modules[moduleName] = requireModule(fileName).default
})
export default modules
- 动态注册store模块:
javascript复制// src/store/index.js
import modules from '@/modules'
Object.keys(modules).forEach(moduleName => {
if (modules[moduleName].store) {
store.registerModule(moduleName, modules[moduleName].store)
}
})
12.2 微前端集成方案
- 使用qiankun框架集成微前端:
bash复制npm install qiankun -S
- 主应用配置:
javascript复制import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
{
name: 'vue-subapp',
entry: '//localhost:7101',
container: '#subapp-container',
activeRule: '/vue'
}
])
start()
- 子应用配置(vue.config.js):
javascript复制module.exports = {
devServer: {
port: 7101,
headers: {
'Access-Control-Allow-Origin': '*'
}
},
configureWebpack: {
output: {
library: 'vueApp',
libraryTarget: 'umd'
}
}
}
12.3 前后端分离实践
- API接口管理方案:
javascript复制// src/api/modules/user.js
import request from '@/utils/request'
export function login(data) {
return request({
url: '/auth/login',
method: 'post',
data
})
}
export function getUserInfo() {
return request({
url: '/user/info',
method: 'get'
})
}
- Mock数据方案:
bash复制npm install mockjs -D
配置:
javascript复制// src/mock/index.js
import Mock from 'mockjs'
Mock.mock('/api/login', 'post', {
code: 200,
data: {
token: 'mock-token'
}
})
- 接口文档集成:
bash复制npm install swagger-jsdoc swagger-ui-express -D
配置:
javascript复制const swaggerJSDoc = require('swagger-jsdoc')
const swaggerUi = require('swagger-ui-express')
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'API文档',
version: '1.0.0'
}
},
apis: ['./src/api/**/*.js']
}
const swaggerSpec = swaggerJSDoc(options)
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
13. 项目实战案例解析
13.1 电商平台核心模块实现
- 商品列表页优化:
vue复制<template>
<div class="product-list">
<virtual-list
:size="80"
:remain="8"
:items="products"
v-slot="{ item }"
>
<product-card :product="item" />
</virtual-list>
</div>
</template>
<script>
import { getProductList } from '@/api/product'
import VirtualList from 'vue-virtual-scroll-list'
export default {
components: {
VirtualList
},
data() {
return {
products: [],
loading: false,
finished: false,
page: 1
}
},
methods: {
async loadMore() {
if (this.loading || this.finished) return
this.loading = true
try {
const { data } = await getProductList({
page: this.page,
pageSize: 20
})
this.products = [...this.products, ...data.list]
this.page++
this.finished = data.list.length < 20
} finally {
this.loading = false
}
}
}
}
</script>
- 购物车状态管理:
javascript复制// store/modules/cart.js
export default {
namespaced: true,
state: {
items: []
},
mutations: {
ADD_ITEM(state, product) {
const existing = state.items.find(item => item.id === product.id)
if (existing) {
existing.quantity++
} else {
state.items.push({
...product,
quantity: 1
})
}
},
REMOVE_ITEM(state, productId) {
state.items = state.items.filter(item => item.id !== productId)
}
},
getters: {
totalPrice: state => {
return state.items.reduce((total, item) => {
return total + (item.price * item.quantity)
}, 0)
}
}
}
13.2 后台管理系统典型功能
- 动态菜单生成:
javascript复制// 根据权限过滤菜单
function filterAsyncRoutes(routes, roles) {
return routes.filter(route => {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
})
}
// 转换路由为菜单
function generateMenu(routes) {
return routes.map(route => {
const menu = {
path: route.path,
name: route.name,
meta: { ...route.meta },
children: []
}
if (route.children) {
menu.children = generateMenu(route.children)
}
return menu
})
}
- 表单设计器实现:
vue复制<template>
<div class="form-designer">
<div class="widget-panel">
<draggable
v-model="widgets"
group="widgets"
:sort="false"
@end="onDragEnd"
>
<div
v-for="widget in widgets"
:key="widget.type"
class="widget-item"
>
{{ widget.name }}
</div>
</draggable>
</div>
<div class="form-panel">
<draggable
v-model="formItems"
group="widgets"
item-key="id"
>
<template #item="{ element }">
<component
:is="getWidgetComponent(element.type)"
v-bind="element.props"
/>
</template>
</draggable>
</div>
</div>
</template>
13.3 数据可视化大屏
- ECharts集成:
bash复制npm install echarts vue-echarts
封装图表组件:
vue复制<template>
<v-chart
:option="chartOption"
:autoresize="true"
class="chart-container"
/>
</template>
<script>
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { BarChart, LineChart, PieChart } from 'echarts/charts'
import {
TitleComponent,
TooltipComponent,
LegendComponent,
GridComponent
} from 'echarts/components'
import VChart from 'vue-echarts'
use([
CanvasRenderer,
BarChart,
LineChart,
PieChart,
TitleComponent,
TooltipComponent,
LegendComponent,
GridComponent
])
export default {
components: {
VChart
},
props: {
data: {
type: Array,
required: true
}
},
computed: {
chartOption() {
return {
title: {
text: '销售数据统计'
},
tooltip: {},
xAxis: {
data: this.data.map(item => item.month)
},
yAxis: {},
series: [
{
name: '销售额',
type: 'bar',
data: this.data.map(item => item.value)
}
]
}
}
}
}
</script>
- 大屏适配方案:
javascript复制//
