[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site-config":3,"article-hbuilderx和uniapp学习笔记":22,"comments-hbuilderx和uniapp学习笔记":46,"footer-socials":47},{"site_title":4,"site_subtitle":5,"home_intro":6,"avatar":7,"seo_keywords":8,"seo_description":9,"site_subtitle_highlight":10,"home_description":11,"about_name":12,"about_intro":13,"code_comment_2":14,"code_log":15,"code_skills":16,"code_goal":17,"code_comment_1":18,"meteor_density":19,"meteor_max_count":19,"meteor_enabled":20,"meteor_speed":21},"ShineGoldYao","架构代码，","全栈开发者 \u002F 开源爱好者 \u002F 技术探索者","https:\u002F\u002Fforuda.gitee.com\u002Favatar\u002F1762402862010015318\u002F16382196_yaoxingjin_1762402861.png!avatar200","ShiGoldYao,技术博客,全栈开发","专注于前沿技术分享与开源项目展示的个人技术博客","书写未来。","大家好，我是 ShiGoldYao。一名全栈学习与技术爱好者。在这里，我分享关于现代 Web 开发、技术框架学习记录以及极客生活的深度思考。","ShiGoldYao","我是一名全栈技术学习者，对构建高性能、可扩展的现代 Web 应用充满热情。过去一年里，我从初识互联网前后端开发，到逐步沉淀技术体系，始终保持着对前端、后端与工程化的持续探索。\n\n我坚信 “代码如诗”。除了日常学习与项目实践，我也会花大量时间关注开源社区，尝试摸索 WebAssembly、Rust 等前沿技术在浏览器端的更多可能，不断挑战性能与体验的边界。\n\n生活里的我并不只有代码：闲暇时会打打永劫无间，享受博弈与操作的快感；也喜欢打乒乓球，在运动中放松自己；当然，最幸福的时光，还是和女朋友一起慢慢生活、认真恋爱。","\u002F\u002F 🚀 开启学习之旅","","Vue , TypeScript , Nest , Mysql","成为优秀的前端全栈工程师","\u002F\u002F 欢迎来到我的技术世界","3","true","5",{"id":23,"title":24,"slug":25,"coverUrl":15,"summary":15,"content":26,"htmlContent":27,"categoryId":21,"viewCount":28,"likeCount":29,"isTop":30,"isPublish":29,"seoKeywords":15,"seoDescription":15,"publishTime":31,"createTime":32,"updateTime":33,"deleteTime":34,"category":35,"tags":38},"15","HBuilderX、微信开发者工具和uniapp学习笔记","hbuilderx和uniapp学习笔记","# HBuilderX、微信开发者工具和uniapp学习笔记\n\n## 目录\n1. [开发环境搭建](#开发环境搭建)\n2. [HBuilderX详解](#hbuilderx详解)\n3. [微信开发者工具详解](#微信开发者工具详解)\n4. [uniapp基础](#uniapp基础)\n5. [uniapp项目开发](#uniapp项目开发)\n6. [uniapp与Vue差异](#uniapp与vue差异)\n7. [跨平台开发实战](#跨平台开发实战)\n8. [性能优化与调试](#性能优化与调试)\n\n---\n\n## 开发环境搭建\n\n### 1. HBuilderX安装\n\n#### 下载安装\n- 官网下载：https:\u002F\u002Fwww.dcloud.io\u002Fhbuilderx.html\n- 选择标准版或App开发版（推荐App开发版）\n- 支持Windows、macOS、Linux\n\n#### 常用插件安装\n1. **uni-app编译插件**（必装）\n   - 运行到浏览器\n   - 运行到小程序模拟器\n   - 运行到手机或模拟器\n\n2. **其他推荐插件**\n   - SCSS\u002FSASS编译\n   - less编译\n   - git插件\n   - 内置浏览器\n\n#### HBuilderX配置\n```json\n\u002F\u002F settings.json\n{\n  \"editor.fontSize\": 14,\n  \"editor.tabSize\": 2,\n  \"editor.wordWrap\": \"on\",\n  \"editor.formatOnSave\": true,\n  \"editor.minimap.enabled\": true\n}\n```\n\n### 2. 微信开发者工具安装\n\n#### 下载安装\n- 官网下载：https:\u002F\u002Fdevelopers.weixin.qq.com\u002Fminiprogram\u002Fdev\u002Fdevtools\u002Fdownload.html\n- 支持Windows、macOS\n\n#### 基本配置\n```json\n\u002F\u002F project.config.json\n{\n  \"miniprogramRoot\": \".\u002Fdist\u002Fdev\u002Fmp-weixin\u002F\",\n  \"cloudfunctionRoot\": \"\",\n  \"setting\": {\n    \"urlCheck\": false,\n    \"es6\": true,\n    \"postcss\": true,\n    \"minified\": true\n  },\n  \"appid\": \"your-appid\",\n  \"projectname\": \"uniapp-project\"\n}\n```\n\n#### 开启服务端口\n- 设置 -> 安全设置 -> 安全 -> 开启服务端口\n- 用于HBuilderX自动打开微信开发者工具\n\n### 3. 环境配置检查\n\n```bash\n# 检查Node.js版本（建议12+）\nnode -v\n\n# 检查npm版本\nnpm -v\n\n# 配置淘宝镜像（可选）\nnpm config set registry https:\u002F\u002Fregistry.npmmirror.com\n```\n\n---\n\n## HBuilderX详解\n\n### 1. 界面介绍\n\n#### 主要区域\n- **左侧项目管理器**：文件树结构\n- **中间编辑区**：代码编辑\n- **右侧工具栏**：运行、发行等\n- **底部控制台**：日志输出\n\n#### 常用快捷键\n```\nCtrl+N      新建文件\nCtrl+S      保存文件\nCtrl+D      选中单词\nCtrl+F      查找\nCtrl+H      替换\nCtrl+G      跳转行\nCtrl+\u002F      注释\nCtrl+Shift+R 格式化代码\nAlt+Shift+F 格式化选中代码\n```\n\n### 2. 项目创建\n\n#### 创建uni-app项目\n1. 文件 -> 新建 -> 项目\n2. 选择uni-app\n3. 选择模板（默认模板、Hello uni-app等）\n4. 填写项目名称和路径\n\n#### 项目结构\n```\nmy-uniapp\u002F\n├── pages\u002F              # 页面文件\n│   ├── index\u002F\n│   │   └── index.vue\n│   └── login\u002F\n│       └── login.vue\n├── static\u002F             # 静态资源\n│   ├── images\u002F\n│   └── fonts\u002F\n├── components\u002F         # 组件\n│   └── my-component\u002F\n│       └── my-component.vue\n├── uni_modules\u002F        # uni-app插件\n├── App.vue             # 应用配置\n├── main.js             # 入口文件\n├── manifest.json       # 应用配置\n├── pages.json          # 页面路由配置\n└── package.json        # 依赖配置\n```\n\n### 3. 运行和调试\n\n#### 运行到浏览器\n- 点击工具栏 -> 运行 -> 运行到浏览器 -> Chrome\n- 支持实时预览\n\n#### 运行到微信开发者工具\n- 点击工具栏 -> 运行 -> 运行到小程序模拟器 -> 微信开发者工具\n- 自动打开微信开发者工具\n\n#### 运行到手机\n- 连接手机，开启USB调试\n- 点击工具栏 -> 运行 -> 运行到手机或模拟器\n\n### 4. 代码提示和智能感知\n\n#### 内置代码块\n- 输入 `uview` 生成视图模板\n- 输入 `uinput` 生成输入框\n- 输入 `uimage` 生成图片\n- 输入 `uapi` 生成API调用模板\n\n#### 自定义代码块\n```json\n\u002F\u002F settings.json -> snippets\n{\n  \"Vue Template\": {\n    \"prefix\": \"vtemp\",\n    \"body\": [\n      \"\u003Ctemplate>\",\n      \"\\t\u003Cview class=\\\"container\\\">\",\n      \"\\t\\t\",\n      \"\\t\u003C\u002Fview>\",\n      \"\u003C\u002Ftemplate>\",\n      \"\",\n      \"\u003Cscript>\",\n      \"export default {\",\n      \"\\tdata() {\",\n      \"\\t\\treturn {\",\n      \"\\t\\t\\t\",\n      \"\\t\\t}\",\n      \"\\t},\",\n      \"\\tonLoad() {\",\n      \"\\t\\t\",\n      \"\\t}\",\n      \"}\",\n      \"\u003C\u002Fscript>\",\n      \"\",\n      \"\u003Cstyle>\",\n      \".container {\",\n      \"\\t\",\n      \"}\",\n      \"\u003C\u002Fstyle>\"\n    ]\n  }\n}\n```\n\n---\n\n## 微信开发者工具详解\n\n### 1. 界面介绍\n\n#### 主要区域\n- **模拟器**：小程序预览\n- **编辑器**：代码编辑（可选）\n- **调试器**：调试工具\n\n#### 调试器功能\n- **Console**：控制台输出\n- **Sources**：源代码调试\n- **Network**：网络请求\n- **Storage**：本地存储\n- **AppData**：页面数据\n- **Wxml**：元素结构\n- **Sensor**：传感器模拟\n\n### 2. 常用功能\n\n#### 真机调试\n- 点击工具栏 -> 真机调试\n- 扫码连接手机\n\n#### 性能监控\n- 工具栏 -> 性能监控\n- 查看FPS、内存使用等\n\n#### 代码上传\n- 工具栏 -> 上传\n- 填写版本号和备注\n\n#### 预览\n- 工具栏 -> 预览\n- 扫码在手机上预览\n\n### 3. 调试技巧\n\n#### Console调试\n```javascript\nconsole.log('普通日志')\nconsole.warn('警告信息')\nconsole.error('错误信息')\nconsole.table(data)  \u002F\u002F 表格形式输出\nconsole.time('timer')\nconsole.timeEnd('timer')\n```\n\n#### 断点调试\n- 在编辑器中点击行号设置断点\n- 使用debugger语句\n```javascript\ndebugger  \u002F\u002F 程序会在此处暂停\n```\n\n#### 网络请求调试\n- Network面板查看所有请求\n- 查看请求头、响应体、时间等\n\n### 4. 常见问题解决\n\n#### 端口占用\n```\n错误：服务端口未开启\n解决：设置 -> 安全设置 -> 开启服务端口\n```\n\n#### 域名白名单\n```\n错误：不在以下request合法域名列表中\n解决：开发阶段可关闭域名校验（详情 -> 本地设置 -> 不校验合法域名）\n```\n\n#### 缓存问题\n```\n解决：工具 -> 清缓存 -> 清除全部缓存\n```\n\n---\n\n## uniapp基础\n\n### 1. 什么是uni-app\n\nuni-app是一个使用Vue.js开发所有前端应用的框架，开发者编写一套代码，可发布到iOS、Android、Web（响应式）、以及各种小程序（微信\u002F支付宝\u002F百度\u002F头条\u002FQQ\u002F钉钉\u002F淘宝）、快应用等多个平台。\n\n### 2. 核心特性\n\n- **跨平台**：一套代码，多端运行\n- **Vue生态**：基于Vue.js，学习成本低\n- **原生体验**：调用原生能力，性能接近原生\n- **丰富组件**：内置大量组件和API\n- **插件市场**：丰富的插件生态\n\n### 3. 支持平台\n\n| 平台 | 支持情况 |\n|------|----------|\n| 微信小程序 | ✓ |\n| 支付宝小程序 | ✓ |\n| 百度小程序 | ✓ |\n| 字节跳动小程序 | ✓ |\n| QQ小程序 | ✓ |\n| H5 | ✓ |\n| Android App | ✓ |\n| iOS App | ✓ |\n\n### 4. 项目配置\n\n#### manifest.json\n```json\n{\n  \"name\": \"uni-app\",\n  \"appid\": \"__UNI__XXXXXX\",\n  \"versionName\": \"1.0.0\",\n  \"versionCode\": \"100\",\n  \"mp-weixin\": {\n    \"appid\": \"wx1234567890abcdef\",\n    \"setting\": {\n      \"urlCheck\": false\n    },\n    \"usingComponents\": true\n  },\n  \"h5\": {\n    \"title\": \"uni-app H5\",\n    \"domain\": \"\"\n  }\n}\n```\n\n#### pages.json\n```json\n{\n  \"pages\": [\n    {\n      \"path\": \"pages\u002Findex\u002Findex\",\n      \"style\": {\n        \"navigationBarTitleText\": \"首页\",\n        \"navigationBarBackgroundColor\": \"#007AFF\",\n        \"navigationBarTextStyle\": \"white\"\n      }\n    },\n    {\n      \"path\": \"pages\u002Flogin\u002Flogin\",\n      \"style\": {\n        \"navigationBarTitleText\": \"登录\"\n      }\n    }\n  ],\n  \"globalStyle\": {\n    \"navigationBarTextStyle\": \"black\",\n    \"navigationBarTitleText\": \"uni-app\",\n    \"navigationBarBackgroundColor\": \"#F8F8F8\",\n    \"backgroundColor\": \"#F8F8F8\"\n  },\n  \"tabBar\": {\n    \"color\": \"#7A7E83\",\n    \"selectedColor\": \"#007AFF\",\n    \"borderStyle\": \"black\",\n    \"backgroundColor\": \"#F8F8F8\",\n    \"list\": [\n      {\n        \"pagePath\": \"pages\u002Findex\u002Findex\",\n        \"iconPath\": \"static\u002Ftab-home.png\",\n        \"selectedIconPath\": \"static\u002Ftab-home-active.png\",\n        \"text\": \"首页\"\n      },\n      {\n        \"pagePath\": \"pages\u002Fuser\u002Fuser\",\n        \"iconPath\": \"static\u002Ftab-user.png\",\n        \"selectedIconPath\": \"static\u002Ftab-user-active.png\",\n        \"text\": \"我的\"\n      }\n    ]\n  }\n}\n```\n\n---\n\n## uniapp项目开发\n\n### 1. 页面开发\n\n#### 基本页面结构\n```vue\n\u003Ctemplate>\n  \u003Cview class=\"container\">\n    \u003Cview class=\"header\">{{ title }}\u003C\u002Fview>\n    \u003Cview class=\"content\">\n      \u003Ctext>{{ message }}\u003C\u002Ftext>\n    \u003C\u002Fview>\n  \u003C\u002Fview>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  data() {\n    return {\n      title: 'uni-app',\n      message: 'Hello uni-app!'\n    }\n  },\n  onLoad(options) {\n    console.log('页面加载', options)\n  },\n  onShow() {\n    console.log('页面显示')\n  },\n  onReady() {\n    console.log('页面渲染完成')\n  },\n  onHide() {\n    console.log('页面隐藏')\n  },\n  onUnload() {\n    console.log('页面卸载')\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle>\n.container {\n  padding: 20rpx;\n}\n.header {\n  font-size: 36rpx;\n  font-weight: bold;\n}\n\u003C\u002Fstyle>\n```\n\n### 2. 常用组件\n\n#### 视图容器\n```vue\n\u003C!-- view -->\n\u003Cview class=\"box\">容器\u003C\u002Fview>\n\n\u003C!-- scroll-view -->\n\u003Cscroll-view scroll-y style=\"height: 300rpx;\">\n  \u003Cview v-for=\"item in 10\" :key=\"item\">内容 {{ item }}\u003C\u002Fview>\n\u003C\u002Fscroll-view>\n\n\u003C!-- swiper -->\n\u003Cswiper indicator-dots autoplay circular>\n  \u003Cswiper-item v-for=\"(item, index) in bannerList\" :key=\"index\">\n    \u003Cimage :src=\"item\" mode=\"aspectFill\">\u003C\u002Fimage>\n  \u003C\u002Fswiper-item>\n\u003C\u002Fswiper-view>\n\n\u003C!-- rich-text -->\n\u003Crich-text :nodes=\"htmlContent\">\u003C\u002Frich-text>\n```\n\n#### 基础内容\n```vue\n\u003C!-- text -->\n\u003Ctext selectable>可选中的文本\u003C\u002Ftext>\n\n\u003C!-- image -->\n\u003Cimage src=\"\u002Fstatic\u002Flogo.png\" mode=\"aspectFit\">\u003C\u002Fimage>\n\n\u003C!-- icon -->\n\u003Cicon type=\"success\" size=\"20\">\u003C\u002Ficon>\n\n\u003C!-- progress -->\n\u003Cprogress percent=\"20\" show-info stroke-width=\"10\">\u003C\u002Fprogress>\n```\n\n#### 表单组件\n```vue\n\u003C!-- button -->\n\u003Cbutton type=\"primary\" @click=\"handleClick\">主要按钮\u003C\u002Fbutton>\n\n\u003C!-- input -->\n\u003Cinput v-model=\"inputValue\" placeholder=\"请输入内容\" \u002F>\n\n\u003C!-- textarea -->\n\u003Ctextarea v-model=\"textValue\" placeholder=\"多行文本\" \u002F>\n\n\u003C!-- checkbox -->\n\u003Ccheckbox-group @change=\"checkboxChange\">\n  \u003Clabel v-for=\"item in items\" :key=\"item.value\">\n    \u003Ccheckbox :value=\"item.value\" :checked=\"item.checked\" \u002F>\n    {{ item.name }}\n  \u003C\u002Flabel>\n\u003C\u002Fcheckbox-group>\n\n\u003C!-- radio -->\n\u003Cradio-group @change=\"radioChange\">\n  \u003Clabel v-for=\"item in items\" :key=\"item.value\">\n    \u003Cradio :value=\"item.value\" :checked=\"item.checked\" \u002F>\n    {{ item.name }}\n  \u003C\u002Flabel>\n\u003C\u002Fradio-group>\n\n\u003C!-- switch -->\n\u003Cswitch :checked=\"switchValue\" @change=\"switchChange\" \u002F>\n\n\u003C!-- picker -->\n\u003Cpicker mode=\"selector\" :range=\"array\" @change=\"pickerChange\">\n  \u003Cview>当前选择：{{ array[pickerIndex] }}\u003C\u002Fview>\n\u003C\u002Fpicker>\n\n\u003C!-- slider -->\n\u003Cslider :value=\"sliderValue\" @change=\"sliderChange\" \u002F>\n```\n\n#### 导航组件\n```vue\n\u003C!-- navigator -->\n\u003Cnavigator url=\"\u002Fpages\u002Fdetail\u002Fdetail?id=123\" open-type=\"navigate\">\n  跳转到详情页\n\u003C\u002Fnavigator>\n\n\u003Cnavigator url=\"\u002Fpages\u002Fdetail\u002Fdetail\" open-type=\"switchTab\">\n  跳转到TabBar页面\n\u003C\u002Fnavigator>\n```\n\n### 3. 常用API\n\n#### 网络请求\n```javascript\nuni.request({\n  url: 'https:\u002F\u002Fapi.example.com\u002Fdata',\n  method: 'GET',\n  data: {\n    id: 1\n  },\n  header: {\n    'content-type': 'application\u002Fjson'\n  },\n  success: (res) => {\n    console.log(res.data)\n  },\n  fail: (err) => {\n    console.error(err)\n  }\n})\n\n\u002F\u002F Promise风格\nuni.request({\n  url: 'https:\u002F\u002Fapi.example.com\u002Fdata'\n}).then(res => {\n  console.log(res.data)\n}).catch(err => {\n  console.error(err)\n})\n\n\u002F\u002F async\u002Fawait\nasync function fetchData() {\n  try {\n    const res = await uni.request({\n      url: 'https:\u002F\u002Fapi.example.com\u002Fdata'\n    })\n    console.log(res.data)\n  } catch (err) {\n    console.error(err)\n  }\n}\n```\n\n#### 页面跳转\n```javascript\n\u002F\u002F 保留当前页面，跳转到应用内的某个页面\nuni.navigateTo({\n  url: '\u002Fpages\u002Fdetail\u002Fdetail?id=123'\n})\n\n\u002F\u002F 关闭当前页面，跳转到应用内的某个页面\nuni.redirectTo({\n  url: '\u002Fpages\u002Fdetail\u002Fdetail'\n})\n\n\u002F\u002F 跳转到tabBar页面，并关闭其他所有非tabBar页面\nuni.switchTab({\n  url: '\u002Fpages\u002Findex\u002Findex'\n})\n\n\u002F\u002F 关闭所有页面，打开到应用内的某个页面\nuni.reLaunch({\n  url: '\u002Fpages\u002Findex\u002Findex'\n})\n\n\u002F\u002F 返回上一页面\nuni.navigateBack({\n  delta: 1\n})\n```\n\n#### 数据存储\n```javascript\n\u002F\u002F 同步存储\nuni.setStorageSync('key', 'value')\nconst value = uni.getStorageSync('key')\nuni.removeStorageSync('key')\nuni.clearStorageSync()\n\n\u002F\u002F 异步存储\nuni.setStorage({\n  key: 'key',\n  data: 'value',\n  success: () => {\n    console.log('存储成功')\n  }\n})\n\nuni.getStorage({\n  key: 'key',\n  success: (res) => {\n    console.log(res.data)\n  }\n})\n```\n\n#### 提示框\n```javascript\n\u002F\u002F 消息提示\nuni.showToast({\n  title: '操作成功',\n  icon: 'success',\n  duration: 2000\n})\n\n\u002F\u002F 加载提示\nuni.showLoading({\n  title: '加载中...'\n})\n\n\u002F\u002F 隐藏加载\nuni.hideLoading()\n\n\u002F\u002F 模态框\nuni.showModal({\n  title: '提示',\n  content: '确定要删除吗？',\n  success: (res) => {\n    if (res.confirm) {\n      console.log('用户点击确定')\n    } else if (res.cancel) {\n      console.log('用户点击取消')\n    }\n  }\n})\n\n\u002F\u002F 操作菜单\nuni.showActionSheet({\n  itemList: ['选项1', '选项2', '选项3'],\n  success: (res) => {\n    console.log('选中了第' + (res.tapIndex + 1) + '个按钮')\n  }\n})\n```\n\n#### 系统信息\n```javascript\n\u002F\u002F 获取系统信息\nconst systemInfo = uni.getSystemInfoSync()\nconsole.log(systemInfo.platform)      \u002F\u002F 平台\nconsole.log(systemInfo.system)        \u002F\u002F 操作系统\nconsole.log(systemInfo.model)         \u002F\u002F 设备型号\nconsole.log(systemInfo.pixelRatio)    \u002F\u002F 设备像素比\nconsole.log(systemInfo.screenWidth)   \u002F\u002F 屏幕宽度\nconsole.log(systemInfo.screenHeight)  \u002F\u002F 屏幕高度\n\n\u002F\u002F 获取网络状态\nuni.getNetworkType({\n  success: (res) => {\n    console.log(res.networkType)  \u002F\u002F wifi、4g、none等\n  }\n})\n\n\u002F\u002F 监听网络状态变化\nuni.onNetworkStatusChange((res) => {\n  console.log(res.isConnected)\n  console.log(res.networkType)\n})\n```\n\n#### 媒体API\n```javascript\n\u002F\u002F 选择图片\nuni.chooseImage({\n  count: 9,\n  sizeType: ['original', 'compressed'],\n  sourceType: ['album', 'camera'],\n  success: (res) => {\n    console.log(res.tempFilePaths)\n  }\n})\n\n\u002F\u002F 预览图片\nuni.previewImage({\n  urls: ['https:\u002F\u002Fexample.com\u002Fimage1.jpg', 'https:\u002F\u002Fexample.com\u002Fimage2.jpg'],\n  current: 0\n})\n\n\u002F\u002F 上传文件\nuni.uploadFile({\n  url: 'https:\u002F\u002Fapi.example.com\u002Fupload',\n  filePath: tempFilePath,\n  name: 'file',\n  success: (res) => {\n    console.log(res.data)\n  }\n})\n\n\u002F\u002F 下载文件\nuni.downloadFile({\n  url: 'https:\u002F\u002Fexample.com\u002Ffile.pdf',\n  success: (res) => {\n    console.log(res.tempFilePath)\n  }\n})\n```\n\n### 4. 条件编译\n\n#### 平台判断\n```javascript\n\u002F\u002F #ifdef H5\nconsole.log('只在H5平台执行')\n\u002F\u002F #endif\n\n\u002F\u002F #ifndef H5\nconsole.log('不在H5平台执行')\n\u002F\u002F #endif\n\n\u002F\u002F #ifdef MP-WEIXIN\nconsole.log('只在微信小程序执行')\n\u002F\u002F #endif\n\n\u002F\u002F #ifdef APP-PLUS\nconsole.log('只在App执行')\n\u002F\u002F #endif\n```\n\n#### 模板条件编译\n```vue\n\u003Ctemplate>\n  \u003Cview>\n    \u003C!-- #ifdef H5 -->\n    \u003Cview>H5平台显示\u003C\u002Fview>\n    \u003C!-- #endif -->\n    \n    \u003C!-- #ifdef MP-WEIXIN -->\n    \u003Cview>微信小程序显示\u003C\u002Fview>\n    \u003C!-- #endif -->\n  \u003C\u002Fview>\n\u003C\u002Ftemplate>\n```\n\n#### 样式条件编译\n```css\n\u002F* #ifdef H5 *\u002F\n.container {\n  background-color: #f0f0f0;\n}\n\u002F* #endif *\u002F\n\n\u002F* #ifdef MP-WEIXIN *\u002F\n.container {\n  background-color: #ffffff;\n}\n\u002F* #endif *\u002F\n```\n\n---\n\n## uniapp与Vue差异\n\n### 1. 标签差异\n\n### Vue标签\n| Vue标签 | uni-app标签 | 说明 |\n|---------|-------------|------|\n| div | view | 容器 |\n| span | text | 文本 |\n| img | image | 图片 |\n| a | navigator | 导航 |\n| input | input | 输入框 |\n| textarea | textarea | 多行文本 |\n| button | button | 按钮 |\n\n### 不支持的Vue标签\n- header, footer, section, article, aside, nav\n- iframe, canvas, video, audio\n- select, option, optgroup\n\n### 2. 样式差异\n\n#### 单位\n```css\n\u002F* 推荐使用rpx单位 *\u002F\n.container {\n  width: 750rpx;  \u002F* 屏幕宽度 *\u002F\n  height: 100rpx;\n}\n\n\u002F* px也会被转换 *\u002F\n.box {\n  font-size: 16px;  \u002F* 在小程序中会转换为rpx *\u002F\n}\n```\n\n#### 选择器限制\n```css\n\u002F* 不支持通配符 * *\u002F\n\u002F* * { margin: 0; }  不支持 *\u002F\n\n\u002F* 不支持属性选择器 *\u002F\n\u002F* input[type=\"text\"] { }  不支持 *\u002F\n\n\u002F* 支持的选择器 *\u002F\n.class { }\n#id { }\nview { }\nview > text { }\nview + view { }\nview text { }\n```\n\n#### 样式隔离\n```vue\n\u003Cstyle scoped>\n\u002F* scoped样式只作用于当前组件 *\u002F\n.container {\n  padding: 20rpx;\n}\n\u003C\u002Fstyle>\n```\n\n### 3. 生命周期差异\n\n#### 应用生命周期\n```javascript\nexport default {\n  onLaunch(options) {\n    \u002F\u002F 应用启动\n  },\n  onShow(options) {\n    \u002F\u002F 应用显示\n  },\n  onHide() {\n    \u002F\u002F 应用隐藏\n  },\n  onError(msg) {\n    \u002F\u002F 应用错误\n  }\n}\n```\n\n#### 页面生命周期\n```javascript\nexport default {\n  onLoad(options) {\n    \u002F\u002F 页面加载\n  },\n  onShow() {\n    \u002F\u002F 页面显示\n  },\n  onReady() {\n    \u002F\u002F 页面渲染完成\n  },\n  onHide() {\n    \u002F\u002F 页面隐藏\n  },\n  onUnload() {\n    \u002F\u002F 页面卸载\n  },\n  onPullDownRefresh() {\n    \u002F\u002F 下拉刷新\n  },\n  onReachBottom() {\n    \u002F\u002F 触底加载更多\n  },\n  onShareAppMessage() {\n    \u002F\u002F 分享\n  },\n  onPageScroll(e) {\n    \u002F\u002F 页面滚动\n  },\n  onResize(size) {\n    \u002F\u002F 页面尺寸变化\n  }\n}\n```\n\n### 4. 指令差异\n\n#### 不支持的指令\n- v-show（小程序不支持）\n- v-html（使用rich-text组件代替）\n\n#### 自定义指令\n```javascript\n\u002F\u002F uni-app不支持自定义指令\n\u002F\u002F Vue自定义指令不适用\n```\n\n### 5. 事件差异\n\n#### 事件绑定\n```vue\n\u003C!-- 阻止冒泡 -->\n\u003Cview @click.stop=\"handleClick\">点击\u003C\u002Fview>\n\n\u003C!-- 阻止默认行为 -->\n\u003Cview @click.prevent=\"handleClick\">点击\u003C\u002Fview>\n\n\u003C!-- 事件捕获 -->\n\u003Cview @click.capture=\"handleClick\">点击\u003C\u002Fview>\n\n\u003C!-- 只触发一次 -->\n\u003Cview @click.once=\"handleClick\">点击\u003C\u002Fview>\n```\n\n#### 触摸事件\n```vue\n\u003Cview \n  @touchstart=\"touchStart\"\n  @touchmove=\"touchMove\"\n  @touchend=\"touchEnd\"\n  @touchcancel=\"touchCancel\"\n>\n  触摸区域\n\u003C\u002Fview>\n```\n\n---\n\n## 跨平台开发实战\n\n### 1. 项目初始化\n\n#### 创建项目\n1. HBuilderX -> 文件 -> 新建 -> 项目\n2. 选择uni-app\n3. 选择默认模板\n4. 填写项目名称：my-uniapp\n\n#### 安装依赖\n```bash\n# 如果使用npm管理依赖\nnpm install\n```\n\n### 2. 目录结构规划\n\n```\nmy-uniapp\u002F\n├── api\u002F                # API接口\n│   ├── user.js\n│   └── product.js\n├── common\u002F             # 公共资源\n│   ├── constants.js    # 常量\n│   ├── utils.js        # 工具函数\n│   └── mixins.js       # 混入\n├── components\u002F         # 组件\n│   ├── nav-bar\u002F        # 导航栏\n│   └── tab-bar\u002F        # 底部导航\n├── pages\u002F              # 页面\n│   ├── index\u002F\n│   ├── user\u002F\n│   └── product\u002F\n├── static\u002F             # 静态资源\n│   ├── images\u002F\n│   ├── icons\u002F\n│   └── fonts\u002F\n├── store\u002F              # 状态管理\n│   └── index.js\n├── styles\u002F             # 全局样式\n│   └── common.scss\n├── uni_modules\u002F        # uni-app插件\n├── App.vue\n├── main.js\n├── manifest.json\n├── pages.json\n└── package.json\n```\n\n### 3. 网络请求封装\n\n#### request.js\n```javascript\nconst BASE_URL = 'https:\u002F\u002Fapi.example.com'\n\nfunction request(options) {\n  return new Promise((resolve, reject) => {\n    uni.request({\n      url: BASE_URL + options.url,\n      method: options.method || 'GET',\n      data: options.data || {},\n      header: {\n        'content-type': 'application\u002Fjson',\n        'Authorization': uni.getStorageSync('token') || ''\n      },\n      success: (res) => {\n        if (res.statusCode === 200) {\n          resolve(res.data)\n        } else {\n          reject(res)\n        }\n      },\n      fail: (err) => {\n        reject(err)\n      }\n    })\n  })\n}\n\nexport default {\n  get(url, data) {\n    return request({ url, method: 'GET', data })\n  },\n  post(url, data) {\n    return request({ url, method: 'POST', data })\n  },\n  put(url, data) {\n    return request({ url, method: 'PUT', data })\n  },\n  delete(url, data) {\n    return request({ url, method: 'DELETE', data })\n  }\n}\n```\n\n#### 使用示例\n```javascript\nimport http from '@\u002Fcommon\u002Frequest.js'\n\nexport default {\n  data() {\n    return {\n      userList: []\n    }\n  },\n  onLoad() {\n    this.fetchUsers()\n  },\n  methods: {\n    async fetchUsers() {\n      try {\n        const res = await http.get('\u002Fusers')\n        this.userList = res.data\n      } catch (err) {\n        console.error(err)\n        uni.showToast({\n          title: '获取数据失败',\n          icon: 'none'\n        })\n      }\n    }\n  }\n}\n```\n\n### 4. 状态管理\n\n#### 简单状态管理\n```javascript\n\u002F\u002F store\u002Findex.js\nconst store = {\n  state: {\n    userInfo: null,\n    token: ''\n  },\n  mutations: {\n    setUserInfo(state, userInfo) {\n      state.userInfo = userInfo\n      uni.setStorageSync('userInfo', userInfo)\n    },\n    setToken(state, token) {\n      state.token = token\n      uni.setStorageSync('token', token)\n    }\n  },\n  actions: {\n    login({ commit }, credentials) {\n      return http.post('\u002Flogin', credentials).then(res => {\n        commit('setToken', res.token)\n        commit('setUserInfo', res.userInfo)\n      })\n    },\n    logout({ commit }) {\n      commit('setToken', '')\n      commit('setUserInfo', null)\n    }\n  }\n}\n\nexport default store\n```\n\n#### 使用Vuex（推荐）\n```javascript\n\u002F\u002F store\u002Findex.js\nimport Vue from 'vue'\nimport Vuex from 'vuex'\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n  state: {\n    userInfo: null,\n    token: ''\n  },\n  mutations: {\n    SET_USER_INFO(state, userInfo) {\n      state.userInfo = userInfo\n    },\n    SET_TOKEN(state, token) {\n      state.token = token\n    }\n  },\n  actions: {\n    async login({ commit }, credentials) {\n      const res = await http.post('\u002Flogin', credentials)\n      commit('SET_TOKEN', res.token)\n      commit('SET_USER_INFO', res.userInfo)\n      return res\n    }\n  },\n  getters: {\n    isLoggedIn: state => !!state.token\n  }\n})\n```\n\n### 5. 组件开发\n\n#### 组件定义\n```vue\n\u003C!-- components\u002Fmy-card\u002Fmy-card.vue -->\n\u003Ctemplate>\n  \u003Cview class=\"my-card\" @click=\"handleClick\">\n    \u003Cimage class=\"card-image\" :src=\"image\" mode=\"aspectFill\">\u003C\u002Fimage>\n    \u003Cview class=\"card-content\">\n      \u003Ctext class=\"card-title\">{{ title }}\u003C\u002Ftext>\n      \u003Ctext class=\"card-desc\">{{ description }}\u003C\u002Ftext>\n    \u003C\u002Fview>\n  \u003C\u002Fview>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: 'MyCard',\n  props: {\n    title: {\n      type: String,\n      default: ''\n    },\n    description: {\n      type: String,\n      default: ''\n    },\n    image: {\n      type: String,\n      default: ''\n    }\n  },\n  methods: {\n    handleClick() {\n      this.$emit('click', this.title)\n    }\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.my-card {\n  background-color: #fff;\n  border-radius: 12rpx;\n  overflow: hidden;\n  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);\n}\n.card-image {\n  width: 100%;\n  height: 300rpx;\n}\n.card-content {\n  padding: 20rpx;\n}\n.card-title {\n  font-size: 32rpx;\n  font-weight: bold;\n  display:block;\n  margin-bottom: 10rpx;\n}\n.card-desc {\n  font-size: 28rpx;\n  color: #666;\n}\n\u003C\u002Fstyle>\n```\n\n#### 组件使用\n```vue\n\u003Ctemplate>\n  \u003Cview>\n    \u003Cmy-card \n      v-for=\"item in list\" \n      :key=\"item.id\"\n      :title=\"item.title\"\n      :description=\"item.description\"\n      :image=\"item.image\"\n      @click=\"handleCardClick\"\n    \u002F>\n  \u003C\u002Fview>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport MyCard from '@\u002Fcomponents\u002Fmy-card\u002Fmy-card.vue'\n\nexport default {\n  components: {\n    MyCard\n  },\n  data() {\n    return {\n      list: []\n    }\n  },\n  methods: {\n    handleCardClick(title) {\n      console.log('点击了卡片：', title)\n    }\n  }\n}\n\u003C\u002Fscript>\n```\n\n### 6. 混入使用\n\n#### 定义混入\n```javascript\n\u002F\u002F common\u002Fmixins.js\nexport const pageMixin = {\n  data() {\n    return {\n      loading: false,\n      page: 1,\n      pageSize: 10,\n      hasMore: true\n    }\n  },\n  methods: {\n    async loadData() {\n      if (this.loading || !this.hasMore) return\n      \n      this.loading = true\n      try {\n        const res = await this.fetchData()\n        this.handleData(res)\n      } catch (err) {\n        console.error(err)\n      } finally {\n        this.loading = false\n      }\n    },\n    onReachBottom() {\n      this.page++\n      this.loadData()\n    }\n  }\n}\n```\n\n#### 使用混入\n```javascript\nimport { pageMixin } from '@\u002Fcommon\u002Fmixins.js'\n\nexport default {\n  mixins: [pageMixin],\n  data() {\n    return {\n      list: []\n    }\n  },\n  methods: {\n    async fetchData() {\n      return http.get('\u002Flist', {\n        page: this.page,\n        pageSize: this.pageSize\n      })\n    },\n    handleData(res) {\n      if (res.data.length \u003C this.pageSize) {\n        this.hasMore = false\n      }\n      this.list = this.list.concat(res.data)\n    }\n  }\n}\n```\n\n---\n\n## 性能优化与调试\n\n### 1. 性能优化\n\n#### 图片优化\n```vue\n\u003C!-- 使用合适的mode -->\n\u003Cimage src=\"logo.png\" mode=\"aspectFit\">\u003C\u002Fimage>\n\n\u003C!-- 懒加载 -->\n\u003Cimage :src=\"item.image\" lazy-load>\u003C\u002Fimage>\n\n\u003C!-- 使用webp格式（支持的平台） -->\n\u003Cimage src=\"image.webp\">\u003C\u002Fimage>\n```\n\n#### 列表优化\n```vue\n\u003C!-- 使用key -->\n\u003Cview v-for=\"item in list\" :key=\"item.id\">\n  {{ item.name }}\n\u003C\u002Fview>\n\n\u003C!-- 长列表使用虚拟滚动 -->\n\u003Crecycle-list :list=\"longList\" :item-height=\"100\">\n  \u003Ctemplate v-slot=\"{ item }\">\n    \u003Cview>{{ item.name }}\u003C\u002Fview>\n  \u003C\u002Ftemplate>\n\u003C\u002Frecycle-list>\n```\n\n#### 数据优化\n```javascript\n\u002F\u002F 避免大对象响应式\n\u002F\u002F 使用Object.freeze冻结不需要响应式的数据\nconst staticData = Object.freeze(largeArray)\n\n\u002F\u002F 合理使用computed\ncomputed: {\n  filteredList() {\n    return this.list.filter(item => item.active)\n  }\n}\n```\n\n#### 代码分包\n```json\n\u002F\u002F pages.json\n{\n  \"pages\": [\n    {\n      \"path\": \"pages\u002Findex\u002Findex\"\n    }\n  ],\n  \"subPackages\": [\n    {\n      \"root\": \"pages\u002Fuser\",\n      \"pages\": [\n        {\n          \"path\": \"profile\u002Fprofile\"\n        },\n        {\n          \"path\": \"settings\u002Fsettings\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n### 2. 调试技巧\n\n#### Console调试\n```javascript\nconsole.log('调试信息')\nconsole.table(data)  \u002F\u002F 表格输出\nconsole.time('timer')\nconsole.timeEnd('timer')\n```\n\n#### 微信开发者工具调试\n- 使用Sources面板打断点\n- 使用AppData查看页面数据\n- 使用Network查看网络请求\n- 使用Performance分析性能\n\n#### vconsole调试\n```javascript\n\u002F\u002F 安HBuilderX插件：vconsole\n\u002F\u002F 在小程序中自动显示调试面板\n```\n\n### 3. 常见问题解决\n\n#### 样式不生效\n```css\n\u002F* 检查选择器是否支持 *\u002F\n\u002F* 检查是否使用了不支持的样式属性 *\u002F\n\u002F* 检查scoped样式是否正确 *\u002F\n```\n\n#### 图片不显示\n```vue\n\u003C!-- 检查图片路径 -->\n\u003C!-- 本地图片放在static目录 -->\n\u003Cimage src=\"\u002Fstatic\u002Flogo.png\">\u003C\u002Fimage>\n\n\u003C!-- 网络图片需要配置域名白名单 -->\n```\n\n#### 跨域问题\n```javascript\n\u002F\u002F H5开发时配置代理\n\u002F\u002F manifest.json -> h5 -> devServer\n{\n  \"h5\": {\n    \"devServer\": {\n      \"proxy\": {\n        \"\u002Fapi\": {\n          \"target\": \"https:\u002F\u002Fapi.example.com\",\n          \"changeOrigin\": true,\n          \"pathRewrite\": {\n            \"^\u002Fapi\": \"\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n#### 小程序审核失败\n```\n常见原因：\n1. 域名未配置白名单\n2. 使用了未授权的API\n3. 内容违规\n4. 功能不完整\n\n解决方案：\n1. 登录微信公众平台配置服务器域名\n2. 检查API使用权限\n3. 审核内容合规性\n4. 完善功能流程\n```\n\n---\n\n## 学习资源\n\n### 官方文档\n- uni-app官方文档：https:\u002F\u002Funiapp.dcloud.net.cn\u002F\n- HBuilderX使用教程：https:\u002F\u002Fhx.dcloud.net.cn\u002F\n- 微信小程序文档：https:\u002F\u002Fdevelopers.weixin.qq.com\u002Fminiprogram\u002Fdev\u002Fframework\u002F\n\n### 插件市场\n- uni-app插件市场：https:\u002F\u002Fext.dcloud.net.cn\u002F\n- 常用插件：uView UI、uni-ui、colorUI等\n\n### 社区资源\n- DCloud社区：https:\u002F\u002Fask.dcloud.net.cn\u002F\n- GitHub：https:\u002F\u002Fgithub.com\u002Fdcloudio\u002Funi-app\n\n---\n\n## 最佳实践\n\n### 1. 开发规范\n- 统一使用rpx单位\n- 组件命名使用kebab-case\n- 页面文件放在pages目录\n- 静态资源放在static目录\n- API接口统一封装\n\n### 2. 代码规范\n- 使用ESLint进行代码检查\n- 统一代码风格\n- 添加必要的注释\n- 合理拆分组件\n\n### 3. 版本管理\n- 使用Git进行版本控制\n- 提交前进行代码review\n- 使用语义化版本号\n- 保留重要版本备份\n\n### 4. 测试策略\n- 多平台测试\n- 边界情况测试\n- 性能测试\n- 兼容性测试\n\n---\n\n## 总结\n\nuni-app是一个强大的跨平台开发框架，结合HBuilderX和微信开发者工具，可以高效地开发小程序、H5和App应用。掌握这些工具的使用方法和uni-app的核心概念，将大大提升开发效率。\n\n**学习路径建议：**\n1. 熟悉HBuilderX基本操作\n2. 掌握微信开发者工具调试\n3. 学习uni-app基础语法\n4. 理解uni-app与Vue的差异\n5. 实战项目开发\n6. 性能优化和问题解决\n",null,104,1,0,"2026-04-07T16:38:10.473Z","2026-04-07T16:38:10.477Z","2026-05-25T22:05:44.322Z","0",{"id":21,"categoryName":36,"slug":36,"description":36,"sort":30,"isEnable":29,"createTime":37,"updateTime":37,"deleteTime":30},"跨端开发","2026-04-07T16:38:39.509Z",[39],{"articleId":23,"tagId":40,"createTime":41,"tag":42},"6","2026-04-07T16:40:32.144Z",{"id":40,"tagName":43,"slug":43,"themeColor":44,"description":43,"createTime":45,"updateTime":45,"deleteTime":34},"Uniapp","#00ff33","2026-04-07T16:40:20.885Z",[],[]]