2.1 UniApp项目结构详解
2.1.1 标准项目目录结构
my-uniapp-project/
├── .hbuilderx/ # HBuilderX配置目录
│ └── launch.json # 运行配置
├── dist/ # 编译输出目录
│ ├── build/ # 构建配置
│ ├── dev/ # 开发模式输出
│ └── h5/ # H5编译输出
├── node_modules/ # 依赖包目录
├── platforms/ # 原生平台代码
│ ├── android/ # Android平台
│ └── ios/ # iOS平台
├── src/ # 源代码目录
│ ├── components/ # 自定义组件
│ │ ├── common/ # 通用组件
│ │ └── business/ # 业务组件
│ ├── pages/ # 页面文件
│ │ ├── index/ # 首页
│ │ │ ├── index.vue
│ │ │ └── index.scss
│ │ └── tabBar/ # 标签页
│ ├── static/ # 静态资源
│ │ ├── images/ # 图片资源
│ │ ├── fonts/ # 字体文件
│ │ └── icons/ # 图标文件
│ ├── store/ # 状态管理
│ │ ├── modules/ # 模块化store
│ │ └── index.js # store入口
│ ├── utils/ # 工具函数
│ │ ├── request.js # 网络请求
│ │ ├── storage.js # 本地存储
│ │ └── common.js # 通用工具
│ ├── mixins/ # 混入文件
│ ├── filters/ # 过滤器
│ ├── directives/ # 自定义指令
│ ├── App.vue # 应用入口组件
│ ├── main.js # 应用入口文件
│ ├── manifest.json # 应用配置
│ ├── pages.json # 页面路由配置
│ └── uni.scss # 全局样式变量
├── .gitignore # Git忽略文件
├── package.json # 项目配置
├── README.md # 项目说明
└── vue.config.js # Vue配置文件
2.1.2 核心文件详解
1. App.vue - 应用入口组件
<template>
<view id="app">
<!-- 应用的根视图 -->
</view>
</template>
<script>
export default {
name: 'App',
// 应用生命周期
onLaunch: function() {
console.log('App Launch')
// 应用启动时执行
this.initApp()
},
onShow: function() {
console.log('App Show')
// 应用显示时执行
},
onHide: function() {
console.log('App Hide')
// 应用隐藏时执行
},
methods: {
initApp() {
// 初始化应用
this.checkUpdate()
this.initGlobalData()
},
checkUpdate() {
// 检查应用更新
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
console.log('当前版本:' + widgetInfo.version)
})
// #endif
},
initGlobalData() {
// 初始化全局数据
this.$store.dispatch('init')
}
}
}
</script>
<style lang="scss">
/* 全局样式 */
@import "@/uni.scss";
#app {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* 通用样式类 */
.container {
padding: 20rpx;
}
.flex {
display: flex;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.text-center {
text-align: center;
}
.text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
2. main.js - 应用入口文件
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
import './utils/permission' // 权限控制
import './utils/interceptor' // 请求拦截器
// 引入全局组件
import CustomButton from '@/components/common/CustomButton.vue'
import LoadingSpinner from '@/components/common/LoadingSpinner.vue'
// 引入全局混入
import globalMixin from '@/mixins/global.js'
// 引入全局过滤器
import * as filters from '@/filters'
// 创建应用实例
const app = createApp(App)
// 使用store
app.use(store)
// 注册全局组件
app.component('CustomButton', CustomButton)
app.component('LoadingSpinner', LoadingSpinner)
// 注册全局混入
app.mixin(globalMixin)
// 注册全局过滤器
Object.keys(filters).forEach(key => {
app.config.globalProperties[`$${key}`] = filters[key]
})
// 全局属性
app.config.globalProperties.$api = require('@/utils/api.js')
app.config.globalProperties.$utils = require('@/utils/common.js')
// 全局错误处理
app.config.errorHandler = (err, vm, info) => {
console.error('全局错误:', err)
console.error('错误信息:', info)
// 错误上报
// reportError(err, info)
}
// 启动应用
app.mount('#app')
// 导出应用实例(用于调试)
export default app
3. manifest.json - 应用配置文件
{
"name": "我的UniApp应用",
"appid": "__UNI__XXXXXXX",
"description": "基于UniApp开发的跨平台应用",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
/* 5+App特有相关 */
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app",
"compilerVersion": 3,
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
},
"modules": {
"Bluetooth": {},
"Camera": {},
"Contacts": {},
"Fingerprint": {},
"iBeacon": {},
"LivePusher": {},
"Maps": {},
"Messaging": {},
"OAuth": {},
"Payment": {},
"Push": {},
"Share": {},
"Speech": {},
"SQLite": {},
"VideoPlayer": {}
},
"distribute": {
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\" />",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\" />",
"<uses-permission android:name=\"android.permission.VIBRATE\" />",
"<uses-permission android:name=\"android.permission.READ_LOGS\" />",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />",
"<uses-feature android:name=\"android.hardware.camera.autofocus\" />",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />",
"<uses-permission android:name=\"android.permission.CAMERA\" />",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\" />",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\" />",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\" />"
],
"abiFilters": ["armeabi-v7a", "arm64-v8a"]
},
"ios": {
"dSYMs": false
},
"sdkConfigs": {
"ad": {},
"maps": {
"amap": {
"appkey_ios": "",
"appkey_android": ""
}
},
"oauth": {
"weixin": {
"appid": "",
"appsecret": ""
},
"qq": {
"appid": ""
},
"sina": {
"appkey": "",
"appsecret": "",
"redirect_uri": ""
}
},
"payment": {
"alipay": {},
"weixin": {
"appid": "",
"mch_id": "",
"key": ""
}
},
"push": {
"unipush": {
"offline": true,
"title": "应用名称",
"channelid": "",
"appkey": "",
"appsecret": ""
}
},
"share": {
"weixin": {
"appid": "",
"appsecret": ""
},
"qq": {
"appid": ""
},
"sina": {
"appkey": "",
"appsecret": "",
"redirect_uri": ""
}
}
}
}
},
/* 快应用特有相关 */
"quickapp": {},
/* 小程序特有相关 */
"mp-weixin": {
"appid": "",
"setting": {
"urlCheck": false,
"es6": true,
"enhance": true,
"postcss": true,
"preloadBackgroundData": false,
"minified": true,
"newFeature": false,
"coverView": true,
"nodeModules": false,
"autoAudits": false,
"showShadowRootInWxmlPanel": true,
"scopeDataCheck": false,
"uglifyFileName": false,
"checkInvalidKey": true,
"checkSiteMap": true,
"uploadWithSourceMap": true,
"compileHotReLoad": false,
"lazyloadPlaceholderEnable": false,
"useMultiFrameRuntime": true,
"useApiHook": true,
"useApiHostProcess": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"enableEngineNative": false,
"useIsolateContext": true,
"userConfirmedBundleSwitch": false,
"packNpmManually": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"disableUseStrict": false,
"minifyWXML": true,
"showES6CompileOption": false,
"useCompilerPlugins": false
},
"usingComponents": true,
"permission": {
"scope.userLocation": {
"desc": "您的位置信息将用于小程序位置接口的效果展示"
}
},
"requiredPrivateInfos": ["getLocation"]
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"vueVersion": "3"
}
4. pages.json - 页面路由配置
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页",
"enablePullDownRefresh": true,
"onReachBottomDistance": 50,
"backgroundTextStyle": "dark"
}
},
{
"path": "pages/category/category",
"style": {
"navigationBarTitleText": "分类",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/cart/cart",
"style": {
"navigationBarTitleText": "购物车",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/profile/profile",
"style": {
"navigationBarTitleText": "我的",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "UniApp应用",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"backgroundTextStyle": "light",
"enablePullDownRefresh": false,
"onReachBottomDistance": 50,
"maxWidth": 375,
"rpxCalcMaxDeviceWidth": 960,
"rpxCalcBaseDeviceWidth": 375,
"rpxCalcIncludeWidth": 750
},
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"height": "50px",
"fontSize": "10px",
"iconWidth": "24px",
"spacing": "3px",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "static/tab-home.png",
"selectedIconPath": "static/tab-home-current.png",
"text": "首页"
},
{
"pagePath": "pages/category/category",
"iconPath": "static/tab-category.png",
"selectedIconPath": "static/tab-category-current.png",
"text": "分类"
},
{
"pagePath": "pages/cart/cart",
"iconPath": "static/tab-cart.png",
"selectedIconPath": "static/tab-cart-current.png",
"text": "购物车"
},
{
"pagePath": "pages/profile/profile",
"iconPath": "static/tab-profile.png",
"selectedIconPath": "static/tab-profile-current.png",
"text": "我的"
}
]
},
"condition": {
"current": 0,
"list": [
{
"name": "首页",
"path": "pages/index/index",
"query": ""
},
{
"name": "登录页",
"path": "pages/login/login",
"query": ""
}
]
},
"subPackages": [
{
"root": "pagesA",
"pages": [
{
"path": "detail/detail",
"style": {
"navigationBarTitleText": "详情页"
}
}
]
},
{
"root": "pagesB",
"pages": [
{
"path": "order/order",
"style": {
"navigationBarTitleText": "订单页"
}
}
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pagesA"]
}
}
}
2.1.3 静态资源管理
1. 图片资源组织
src/
├── components/ # 组件目录
│ ├── common/ # 通用组件
│ └── business/ # 业务组件
├── pages/ # 页面目录
├── static/ # 静态资源
├── store/ # 状态管理
├── utils/ # 工具函数
├── api/ # API接口
├── mixins/ # 混入
├── filters/ # 过滤器
├── App.vue # 应用入口
├── main.js # 入口文件
├── manifest.json # 应用配置
└── pages.json # 页面配置
快速开始
安装依赖
npm install
开发模式
# H5开发
npm run dev:h5
# 微信小程序开发
npm run dev:mp-weixin
# App开发
npm run dev:app-plus
构建发布
# 构建H5
npm run build:h5
# 构建微信小程序
npm run build:mp-weixin
# 构建App
npm run build:app-plus
开发规范
代码规范
- 使用ESLint进行代码检查
- 使用Prettier进行代码格式化
- 遵循Vue官方风格指南
- 使用语义化的命名
提交规范
feat: 新功能
fix: 修复bug
docs: 文档更新
style: 代码格式调整
refactor: 代码重构
test: 测试相关
chore: 构建过程或辅助工具的变动
常见问题
开发环境问题
Node.js版本兼容性
- 推荐使用Node.js 14.x或16.x
- 避免使用过新或过旧的版本
依赖安装失败
- 清除缓存:
npm cache clean --force
- 删除node_modules重新安装
- 使用cnpm或yarn替代npm
- 清除缓存:
编译错误
- 检查语法错误
- 确认依赖版本兼容性
- 查看控制台错误信息
运行问题
页面白屏
- 检查路由配置
- 确认页面文件存在
- 查看控制台错误
样式不生效
- 检查CSS语法
- 确认样式文件引入
- 验证选择器优先级
API请求失败
- 检查网络连接
- 确认接口地址正确
- 验证请求参数
性能优化建议
代码优化
- 组件懒加载
- 图片压缩和懒加载
- 减少不必要的计算
- 合理使用缓存
包体积优化
- 按需引入第三方库
- 移除未使用的代码
- 使用分包加载
- 压缩静态资源
更新日志
v1.0.0 (2024-01-01)
- 初始版本发布
- 基础功能实现
- 多端适配完成
贡献指南
- Fork项目
- 创建功能分支
- 提交代码
- 发起Pull Request
许可证
MIT License
---
## 2.5 本章总结
### 2.5.1 学习要点回顾
**1. 项目结构理解**
- 掌握UniApp标准项目目录结构
- 理解核心配置文件的作用
- 学会合理组织代码和资源
- 掌握静态资源管理方法
**2. 开发工具使用**
- 熟练使用HBuilderX开发环境
- 掌握代码提示和补全功能
- 学会调试和预览技巧
- 了解插件和扩展管理
**3. 项目配置优化**
- 掌握编译配置和条件编译
- 学会性能优化配置
- 理解环境变量和配置管理
- 掌握开发环境配置
**4. 代码规范实践**
- 遵循文件命名规范
- 掌握代码风格规范
- 学会编写规范的注释和文档
- 建立良好的开发习惯
### 2.5.2 实践练习
**练习1:项目结构搭建**
```javascript
// 任务:创建一个电商应用的项目结构
// 要求:
// 1. 合理划分目录结构
// 2. 配置必要的配置文件
// 3. 创建基础页面和组件
// 4. 设置开发环境
// 参考结构:
src/
├── components/
│ ├── common/
│ │ ├── BaseButton.vue
│ │ ├── BaseInput.vue
│ │ └── LoadingSpinner.vue
│ └── business/
│ ├── ProductCard.vue
│ ├── CartItem.vue
│ └── OrderStatus.vue
├── pages/
│ ├── index/
│ ├── category/
│ ├── cart/
│ ├── profile/
│ └── product-detail/
├── store/
│ ├── modules/
│ │ ├── user.js
│ │ ├── product.js
│ │ └── cart.js
│ └── index.js
├── utils/
│ ├── request.js
│ ├── storage.js
│ └── common.js
└── api/
├── userApi.js
├── productApi.js
└── orderApi.js
练习2:开发工具配置
// 任务:配置HBuilderX开发环境
// 要求:
// 1. 安装必要的插件
// 2. 配置代码格式化
// 3. 设置代码片段
// 4. 配置调试环境
// 推荐插件列表:
- Prettier代码格式化
- ESLint代码检查
- Auto Rename Tag
- Bracket Pair Colorizer
- GitLens
- Thunder Client
练习3:配置文件编写
// 任务:编写项目配置文件
// 要求:
// 1. 配置manifest.json
// 2. 配置pages.json
// 3. 配置vue.config.js
// 4. 设置环境变量
// 配置要点:
// - 应用基本信息
// - 页面路由配置
// - 编译优化配置
// - 多环境配置
2.5.3 常见问题解答
Q1:如何选择合适的项目结构?
A1:项目结构选择应考虑以下因素: - 项目规模和复杂度 - 团队开发习惯 - 维护和扩展需求 - 性能优化要求
小型项目可使用简单的功能分层结构,大型项目建议使用模块化结构。
Q2:HBuilderX和其他IDE相比有什么优势?
A2:HBuilderX的主要优势: - 专为UniApp优化,提供完整的开发体验 - 内置多端预览和调试功能 - 丰富的代码提示和补全 - 集成的插件生态 - 简化的项目配置和部署流程
Q3:如何处理不同平台的差异化配置?
A3:处理平台差异的方法: - 使用条件编译处理代码差异 - 在manifest.json中配置平台特定选项 - 使用平台检测API动态处理 - 创建平台特定的组件和样式
Q4:项目性能优化有哪些关键点?
A4:性能优化关键点: - 合理的分包策略 - 图片和资源优化 - 代码分割和懒加载 - 缓存策略配置 - 网络请求优化
2.5.4 下章预告
在下一章《基础语法与组件使用》中,我们将学习:
Vue 3基础语法
- 响应式数据
- 计算属性和监听器
- 生命周期钩子
- 组件通信
UniApp内置组件
- 视图容器组件
- 基础内容组件
- 表单组件
- 导航组件
自定义组件开发
- 组件设计原则
- 组件封装技巧
- 组件通信方式
- 组件库构建
样式和布局
- CSS预处理器使用
- 响应式布局
- 主题定制
- 动画效果
通过下一章的学习,你将掌握UniApp开发的核心技能,能够创建功能丰富的用户界面。tatic/ ├── images/ │ ├── common/ # 通用图片 │ │ ├── logo.png │ │ ├── placeholder.png │ │ └── default-avatar.png │ ├── icons/ # 图标文件 │ │ ├── home.png │ │ ├── search.png │ │ └── arrow-right.png │ ├── banners/ # 轮播图 │ │ ├── banner1.jpg │ │ └── banner2.jpg │ └── backgrounds/ # 背景图 │ ├── login-bg.jpg │ └── profile-bg.jpg ├── fonts/ # 字体文件 │ ├── iconfont.ttf │ └── custom-font.woff └── videos/ # 视频文件 └── intro.mp4
**2. 资源引用方式**
```vue
<template>
<view>
<!-- 相对路径引用 -->
<image src="../../static/images/logo.png" />
<!-- 绝对路径引用 -->
<image src="/static/images/logo.png" />
<!-- @符号引用 -->
<image src="@/static/images/logo.png" />
<!-- 网络图片 -->
<image src="https://example.com/image.jpg" />
<!-- 动态绑定 -->
<image :src="imageUrl" />
</view>
</template>
<script>
export default {
data() {
return {
imageUrl: '/static/images/dynamic.png'
}
}
}
</script>
<style>
/* CSS中引用图片 */
.background {
background-image: url('@/static/images/bg.jpg');
}
/* 字体文件引用 */
@font-face {
font-family: 'CustomFont';
src: url('@/static/fonts/custom-font.ttf');
}
</style>
2.2 HBuilderX开发工具深入
2.2.1 界面布局详解
1. 主界面组成
┌─────────────────────────────────────────────────────────┐
│ 菜单栏 (File, Edit, View, Run, Tools, Help) │
├─────────────────────────────────────────────────────────┤
│ 工具栏 (新建, 保存, 运行, 调试等快捷按钮) │
├──────────┬──────────────────────────┬─────────────────────┤
│ │ │ │
│ 项目 │ │ 属性面板 │
│ 管理器 │ 代码编辑区域 │ (可选) │
│ │ │ │
│ │ │ │
├──────────┼──────────────────────────┼─────────────────────┤
│ 文件 │ │ 控制台 │
│ 浏览器 │ │ 输出窗口 │
└──────────┴──────────────────────────┴─────────────────────┘
2. 项目管理器功能
// 项目管理器主要功能
1. 项目树形结构显示
2. 文件/文件夹操作
- 新建、删除、重命名
- 复制、粘贴、移动
- 搜索文件
3. 项目切换
4. Git状态显示
5. 文件类型图标
3. 代码编辑器特性
// 编辑器核心功能
1. 语法高亮
- Vue单文件组件
- JavaScript/TypeScript
- CSS/SCSS/LESS
- JSON配置文件
2. 智能提示
- 代码自动补全
- 参数提示
- 错误检查
- 快速修复建议
3. 代码导航
- 跳转到定义
- 查找引用
- 符号搜索
- 面包屑导航
4. 编辑增强
- 多光标编辑
- 代码折叠
- 括号匹配
- 自动缩进
2.2.2 代码提示和补全
1. Vue组件提示
<template>
<!-- 输入 <uni- 会提示所有uni组件 -->
<uni-list>
<uni-list-item>
<!-- 属性提示 -->
<text :class="textClass">内容</text>
</uni-list-item>
</uni-list>
</template>
<script>
export default {
data() {
return {
// 变量提示
textClass: 'text-primary'
}
},
methods: {
// 方法提示
handleClick() {
// API提示
uni.showToast({
title: '提示',
icon: 'success'
})
}
}
}
</script>
2. API智能提示
// UniApp API提示
uni.request({
url: '', // 自动提示必填参数
method: '', // 提示可选值:GET, POST, PUT, DELETE
data: {},
success: (res) => {
// res参数自动提示
console.log(res.data)
}
})
// 平台API提示
// #ifdef APP-PLUS
plus.device.getInfo({
success: (info) => {
// info参数提示
console.log(info.model)
}
})
// #endif
3. 自定义代码片段
// 在工具 → 代码块设置中添加
{
"vue-page": {
"prefix": "vpage",
"body": [
"<template>",
" <view class=\"container\">",
" $1",
" </view>",
"</template>",
"",
"<script>",
"export default {",
" name: '$2',",
" data() {",
" return {",
" $3",
" }",
" },",
" onLoad() {",
" $4",
" }",
"}",
"</script>",
"",
"<style lang=\"scss\" scoped>",
".container {",
" padding: 20rpx;",
"}",
"</style>"
],
"description": "Vue页面模板"
}
}
2.2.3 调试和预览功能
1. 实时预览配置
// .hbuilderx/launch.json 配置
{
"version": "0.0",
"configurations": [
{
"type": "uniApp",
"default": {
"launchtype": "local"
},
"h5": {
"launchtype": "local",
"port": 8080,
"host": "localhost"
},
"mp-weixin": {
"launchtype": "local",
"port": 9090
},
"app-plus": {
"launchtype": "local",
"android": {
"device": "emulator-5554"
},
"ios": {
"device": "iPhone 12"
}
}
}
]
}
2. 多端同步预览
// 同步预览设置
1. 运行 → 运行到浏览器 → 自动刷新
2. 运行 → 运行到小程序模拟器 → 热重载
3. 运行 → 运行到手机或模拟器 → 真机同步
// 预览模式
- 开发模式:实时编译,支持热重载
- 生产模式:优化编译,用于发布
- 调试模式:包含调试信息,便于排错
3. 断点调试
// 在代码中设置断点
export default {
methods: {
handleSubmit() {
debugger; // 设置断点
const formData = this.getFormData()
console.log('表单数据:', formData) // 查看变量值
this.submitForm(formData)
},
getFormData() {
// 在此行设置断点
return {
name: this.name,
email: this.email
}
}
}
}
2.2.4 插件和扩展管理
1. 内置插件
// 核心插件
1. uni-app语法提示
2. Vue语法支持
3. ES6+语法支持
4. SCSS/LESS编译
5. TypeScript支持
6. 代码格式化
7. Git集成
8. 终端集成
// 调试插件
1. Chrome DevTools
2. 微信开发者工具集成
3. 真机调试
4. 网络抓包
2. 第三方插件安装
// 通过插件市场安装
1. 工具 → 插件安装
2. 搜索插件名称
3. 点击安装
4. 重启HBuilderX
// 推荐插件
- Prettier代码格式化
- ESLint代码检查
- Vetur Vue工具
- Auto Rename Tag
- Bracket Pair Colorizer
- GitLens Git增强
- Thunder Client API测试
3. 插件配置
// settings.json 插件配置
{
"prettier.enable": true,
"prettier.semi": false,
"prettier.singleQuote": true,
"prettier.tabWidth": 2,
"eslint.enable": true,
"eslint.autoFixOnSave": true,
"vetur.format.defaultFormatter.html": "prettier",
"vetur.format.defaultFormatter.js": "prettier",
"vetur.format.defaultFormatter.css": "prettier"
}
2.3 项目配置优化
2.3.1 编译配置
1. vue.config.js配置
const path = require('path')
module.exports = {
// 基础配置
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
outputDir: 'dist',
assetsDir: 'static',
// 开发服务器配置
devServer: {
port: 8080,
host: '0.0.0.0',
https: false,
open: true,
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
},
// 路径别名
configureWebpack: {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@pages': path.resolve(__dirname, 'src/pages'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@static': path.resolve(__dirname, 'src/static')
}
}
},
// CSS配置
css: {
loaderOptions: {
sass: {
prependData: `@import "@/uni.scss";`
}
}
},
// 生产环境优化
chainWebpack: config => {
// 生产环境移除console
if (process.env.NODE_ENV === 'production') {
config.optimization.minimizer('terser').tap((args) => {
args[0].terserOptions.compress.drop_console = true
return args
})
}
// 图片压缩
config.module
.rule('images')
.test(/\.(png|jpe?g|gif|svg)$/)
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
mozjpeg: { progressive: true, quality: 80 },
optipng: { enabled: false },
pngquant: { quality: [0.65, 0.8], speed: 4 },
gifsicle: { interlaced: false }
})
}
}
2. 条件编译配置
// 平台条件编译
// #ifdef H5
console.log('这段代码只在H5平台运行')
// #endif
// #ifdef MP-WEIXIN
console.log('这段代码只在微信小程序运行')
// #endif
// #ifdef APP-PLUS
console.log('这段代码只在App平台运行')
// #endif
// #ifndef H5
console.log('这段代码在除H5外的平台运行')
// #endif
// 多平台条件编译
// #ifdef H5 || MP-WEIXIN
console.log('这段代码在H5或微信小程序运行')
// #endif
<!-- 模板中的条件编译 -->
<template>
<view>
<!-- #ifdef H5 -->
<view class="h5-only">H5专用内容</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<button open-type="getUserInfo" @getuserinfo="getUserInfo">
获取用户信息
</button>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<button @click="openNativeView">打开原生页面</button>
<!-- #endif -->
</view>
</template>
<style>
/* 样式中的条件编译 */
/* #ifdef H5 */
.container {
max-width: 750px;
margin: 0 auto;
}
/* #endif */
/* #ifdef MP-WEIXIN */
.container {
padding-top: 88rpx; /* 微信小程序状态栏高度 */
}
/* #endif */
</style>
2.3.2 性能优化配置
1. 分包配置
// pages.json 中配置分包
{
"pages": [
// 主包页面
{
"path": "pages/index/index",
"style": { "navigationBarTitleText": "首页" }
}
],
"subPackages": [
{
"root": "pagesA",
"name": "pack1",
"pages": [
{
"path": "detail/detail",
"style": { "navigationBarTitleText": "详情" }
},
{
"path": "list/list",
"style": { "navigationBarTitleText": "列表" }
}
]
},
{
"root": "pagesB",
"name": "pack2",
"pages": [
{
"path": "profile/profile",
"style": { "navigationBarTitleText": "个人中心" }
}
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pack1"]
},
"pagesA/list/list": {
"network": "wifi",
"packages": ["pack2"]
}
}
}
2. 资源优化配置
// 图片懒加载配置
const imageConfig = {
// 图片压缩质量
quality: 80,
// 图片格式转换
format: 'webp',
// 响应式图片
responsive: {
small: { width: 300, quality: 70 },
medium: { width: 600, quality: 80 },
large: { width: 1200, quality: 85 }
},
// 懒加载配置
lazyload: {
placeholder: '/static/images/placeholder.png',
error: '/static/images/error.png',
loading: '/static/images/loading.gif'
}
}
// 网络请求优化
const requestConfig = {
// 请求超时时间
timeout: 10000,
// 重试次数
retry: 3,
// 缓存配置
cache: {
enable: true,
maxAge: 5 * 60 * 1000, // 5分钟
maxSize: 50 // 最大缓存50个请求
},
// 请求拦截器
interceptors: {
request: (config) => {
// 添加token
config.header.Authorization = getToken()
return config
},
response: (response) => {
// 统一错误处理
if (response.statusCode !== 200) {
handleError(response)
}
return response
}
}
}
2.3.3 开发环境配置
1. 环境变量配置
// .env.development
VUE_APP_ENV = 'development'
VUE_APP_BASE_URL = 'http://localhost:3000'
VUE_APP_API_URL = 'http://localhost:3000/api'
VUE_APP_UPLOAD_URL = 'http://localhost:3000/upload'
VUE_APP_DEBUG = true
// .env.production
VUE_APP_ENV = 'production'
VUE_APP_BASE_URL = 'https://api.example.com'
VUE_APP_API_URL = 'https://api.example.com/api'
VUE_APP_UPLOAD_URL = 'https://api.example.com/upload'
VUE_APP_DEBUG = false
// .env.test
VUE_APP_ENV = 'test'
VUE_APP_BASE_URL = 'https://test-api.example.com'
VUE_APP_API_URL = 'https://test-api.example.com/api'
VUE_APP_UPLOAD_URL = 'https://test-api.example.com/upload'
VUE_APP_DEBUG = true
2. 配置文件管理
// src/config/index.js
const config = {
development: {
baseURL: process.env.VUE_APP_BASE_URL,
apiURL: process.env.VUE_APP_API_URL,
uploadURL: process.env.VUE_APP_UPLOAD_URL,
debug: process.env.VUE_APP_DEBUG === 'true',
// 开发环境特有配置
mockData: true,
showVConsole: true,
logLevel: 'debug'
},
production: {
baseURL: process.env.VUE_APP_BASE_URL,
apiURL: process.env.VUE_APP_API_URL,
uploadURL: process.env.VUE_APP_UPLOAD_URL,
debug: false,
// 生产环境特有配置
mockData: false,
showVConsole: false,
logLevel: 'error',
// 性能监控
performance: {
enable: true,
reportURL: 'https://monitor.example.com/report'
}
},
test: {
baseURL: process.env.VUE_APP_BASE_URL,
apiURL: process.env.VUE_APP_API_URL,
uploadURL: process.env.VUE_APP_UPLOAD_URL,
debug: true,
// 测试环境特有配置
mockData: false,
showVConsole: true,
logLevel: 'info'
}
}
const currentEnv = process.env.VUE_APP_ENV || 'development'
export default config[currentEnv]
2.4 代码组织最佳实践
2.4.1 文件命名规范
1. 文件命名约定
命名规范:
- 页面文件:kebab-case (user-profile.vue)
- 组件文件:PascalCase (UserProfile.vue)
- 工具文件:camelCase (userUtils.js)
- 常量文件:UPPER_CASE (API_CONSTANTS.js)
- 样式文件:kebab-case (user-profile.scss)
示例结构:
src/
├── components/
│ ├── common/
│ │ ├── BaseButton.vue
│ │ ├── BaseInput.vue
│ │ └── LoadingSpinner.vue
│ └── business/
│ ├── UserCard.vue
│ ├── ProductList.vue
│ └── OrderStatus.vue
├── pages/
│ ├── user-profile/
│ │ ├── user-profile.vue
│ │ └── user-profile.scss
│ └── product-detail/
│ ├── product-detail.vue
│ └── components/
│ ├── ProductInfo.vue
│ └── ProductReviews.vue
├── utils/
│ ├── requestUtils.js
│ ├── storageUtils.js
│ └── dateUtils.js
└── constants/
├── API_CONSTANTS.js
├── ROUTE_CONSTANTS.js
└── STATUS_CONSTANTS.js
2. 目录结构规范
// 按功能模块组织
src/
├── modules/
│ ├── user/
│ │ ├── pages/
│ │ │ ├── profile.vue
│ │ │ └── settings.vue
│ │ ├── components/
│ │ │ ├── UserCard.vue
│ │ │ └── UserForm.vue
│ │ ├── store/
│ │ │ └── userStore.js
│ │ ├── api/
│ │ │ └── userApi.js
│ │ └── utils/
│ │ └── userUtils.js
│ ├── product/
│ │ ├── pages/
│ │ ├── components/
│ │ ├── store/
│ │ ├── api/
│ │ └── utils/
│ └── order/
│ ├── pages/
│ ├── components/
│ ├── store/
│ ├── api/
│ └── utils/
└── shared/
├── components/
├── utils/
├── constants/
└── styles/
2.4.2 代码风格规范
1. Vue组件规范
<!-- 标准Vue组件模板 -->
<template>
<view class="user-profile">
<!-- 使用语义化的class名称 -->
<view class="user-profile__header">
<image
class="user-profile__avatar"
:src="userInfo.avatar"
@error="handleAvatarError"
/>
<text class="user-profile__name">{{ userInfo.name }}</text>
</view>
<view class="user-profile__content">
<!-- 组件内容 -->
</view>
</view>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import UserApi from '@/api/userApi'
import { validateEmail } from '@/utils/validation'
export default {
name: 'UserProfile',
// 组件属性
props: {
userId: {
type: String,
required: true,
validator: (value) => value.length > 0
},
editable: {
type: Boolean,
default: false
}
},
// 组件数据
data() {
return {
loading: false,
userInfo: {
name: '',
email: '',
avatar: ''
}
}
},
// 计算属性
computed: {
...mapState('user', ['currentUser']),
isCurrentUser() {
return this.userId === this.currentUser.id
},
displayName() {
return this.userInfo.name || '未知用户'
}
},
// 监听器
watch: {
userId: {
handler: 'fetchUserInfo',
immediate: true
}
},
// 生命周期
onLoad(options) {
this.initComponent(options)
},
onShow() {
this.refreshUserInfo()
},
// 方法
methods: {
...mapActions('user', ['updateUser']),
async initComponent(options) {
try {
this.loading = true
await this.fetchUserInfo()
} catch (error) {
this.handleError(error)
} finally {
this.loading = false
}
},
async fetchUserInfo() {
const response = await UserApi.getUserInfo(this.userId)
this.userInfo = response.data
},
handleAvatarError() {
this.userInfo.avatar = '/static/images/default-avatar.png'
},
handleError(error) {
console.error('用户信息加载失败:', error)
uni.showToast({
title: '加载失败',
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.user-profile {
padding: 20rpx;
&__header {
display: flex;
align-items: center;
margin-bottom: 30rpx;
}
&__avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
margin-right: 20rpx;
}
&__name {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
&__content {
// 内容样式
}
}
</style>
2. JavaScript代码规范
// utils/requestUtils.js
/**
* 网络请求工具类
* @description 封装uni.request,提供统一的请求接口
*/
class RequestUtils {
constructor() {
this.baseURL = process.env.VUE_APP_API_URL
this.timeout = 10000
this.defaultHeaders = {
'Content-Type': 'application/json'
}
}
/**
* 发送GET请求
* @param {string} url - 请求地址
* @param {Object} params - 请求参数
* @param {Object} options - 请求选项
* @returns {Promise} 请求结果
*/
async get(url, params = {}, options = {}) {
return this.request({
url,
method: 'GET',
data: params,
...options
})
}
/**
* 发送POST请求
* @param {string} url - 请求地址
* @param {Object} data - 请求数据
* @param {Object} options - 请求选项
* @returns {Promise} 请求结果
*/
async post(url, data = {}, options = {}) {
return this.request({
url,
method: 'POST',
data,
...options
})
}
/**
* 通用请求方法
* @param {Object} config - 请求配置
* @returns {Promise} 请求结果
*/
async request(config) {
// 请求拦截
const requestConfig = this.interceptRequest(config)
try {
const response = await uni.request(requestConfig)
// 响应拦截
return this.interceptResponse(response)
} catch (error) {
return this.handleError(error)
}
}
/**
* 请求拦截器
* @param {Object} config - 请求配置
* @returns {Object} 处理后的配置
*/
interceptRequest(config) {
// 添加基础URL
if (!config.url.startsWith('http')) {
config.url = this.baseURL + config.url
}
// 添加默认headers
config.header = {
...this.defaultHeaders,
...config.header
}
// 添加认证token
const token = uni.getStorageSync('token')
if (token) {
config.header.Authorization = `Bearer ${token}`
}
// 设置超时时间
config.timeout = config.timeout || this.timeout
return config
}
/**
* 响应拦截器
* @param {Object} response - 响应对象
* @returns {Object} 处理后的响应
*/
interceptResponse(response) {
const { statusCode, data } = response
// 请求成功
if (statusCode === 200) {
// 业务逻辑成功
if (data.code === 0) {
return data
}
// 业务逻辑失败
throw new Error(data.message || '请求失败')
}
// HTTP状态码错误
throw new Error(this.getErrorMessage(statusCode))
}
/**
* 错误处理
* @param {Error} error - 错误对象
* @returns {Promise} 拒绝的Promise
*/
handleError(error) {
console.error('请求错误:', error)
// 显示错误提示
uni.showToast({
title: error.message || '网络错误',
icon: 'none',
duration: 2000
})
return Promise.reject(error)
}
/**
* 获取错误信息
* @param {number} statusCode - HTTP状态码
* @returns {string} 错误信息
*/
getErrorMessage(statusCode) {
const errorMessages = {
400: '请求参数错误',
401: '未授权,请重新登录',
403: '拒绝访问',
404: '请求资源不存在',
500: '服务器内部错误',
502: '网关错误',
503: '服务不可用',
504: '网关超时'
}
return errorMessages[statusCode] || '网络错误'
}
}
// 创建实例
const requestUtils = new RequestUtils()
// 导出实例
export default requestUtils
// 导出便捷方法
export const { get, post, put, delete: del } = requestUtils
2.4.3 注释和文档规范
1. 代码注释规范
/**
* 用户管理API
* @module UserApi
* @description 提供用户相关的API接口
* @author 开发者姓名
* @since 1.0.0
*/
/**
* 用户信息接口
* @typedef {Object} UserInfo
* @property {string} id - 用户ID
* @property {string} name - 用户姓名
* @property {string} email - 邮箱地址
* @property {string} avatar - 头像URL
* @property {number} createTime - 创建时间戳
*/
class UserApi {
/**
* 获取用户信息
* @async
* @function getUserInfo
* @param {string} userId - 用户ID
* @returns {Promise<UserInfo>} 用户信息
* @throws {Error} 当用户不存在时抛出错误
* @example
* // 获取用户信息
* const userInfo = await UserApi.getUserInfo('123')
* console.log(userInfo.name)
*/
static async getUserInfo(userId) {
// 参数验证
if (!userId) {
throw new Error('用户ID不能为空')
}
try {
// 发送请求
const response = await request.get(`/users/${userId}`)
return response.data
} catch (error) {
// 错误处理
console.error('获取用户信息失败:', error)
throw error
}
}
/**
* 更新用户信息
* @async
* @function updateUserInfo
* @param {string} userId - 用户ID
* @param {Partial<UserInfo>} userInfo - 要更新的用户信息
* @returns {Promise<UserInfo>} 更新后的用户信息
* @example
* // 更新用户姓名
* const updatedUser = await UserApi.updateUserInfo('123', {
* name: '新姓名'
* })
*/
static async updateUserInfo(userId, userInfo) {
// 实现代码...
}
}
export default UserApi
2. README文档规范
# 项目名称
## 项目简介
简要描述项目的功能和特点。
## 技术栈
- UniApp 3.x
- Vue 3.x
- Vuex 4.x
- SCSS
- TypeScript (可选)
## 项目结构
s