Skip to content

项目介绍与 uni-app 基础(二) ​

本页对应 项目介绍与 uni-app 基础,共 7 段视频,约 1 小时 0 分。

学习目标 ​

  • 能够按步骤排查 HBuilder 真机运行失败问题:检查手机授权、撤销授权并重插数据线、切换 USB 调试、重启手机,并说明 iOS 无证书时使用云手机或 H5 调试的替代方案。
  • 能够注册/登录 DCloud 账号,通过 HBuilder 插件安装入口或插件市场搜索并安装 Prettier,并在已安装插件列表中确认安装结果。
  • 能够配置 Prettier 生效范围(如 *.vue、*.js),在项目根目录创建 Prettier 配置文件,并设置缩进、分号、引号、Vue 缩进等常用格式化规则。
  • 能够完成 HBuilder 基本配置:调整字号、将制表符设为 2、勾选空格代替制表符、开启保存时自动格式化、开启折叠最后一行,并按“先配置 Prettier、后开启自动保存”的顺序操作。
  • 能够使用 HBuilder 将 uni-app 运行到真机或云手机,完成上传 APK、进入云手机、安装并启动应用的基本测试流程,并验证页面在多端表现一致。
  • 能够在 uni.scss 中定义全局 SCSS 变量并在页面样式中引用验证生效;能够在 App.vue 的 script 中编写全局生命周期、在 style 中编写全局样式,并说明 App.vue 不能写 template。

知识点 ​

2.1 全局文件:先建立“哪些东西全局生效”的意识 ​

为什么需要:uni-app 组合了 Vue 和微信小程序两套知识。小程序里有 app.js、app.json、app.wxss 这类全局文件;uni-app 也提供对应物。先认清全局文件,才能知道样式、配置、生命周期该写在哪里。

怎么想:把全局文件理解成“项目级入口”:uni.scss 管全局 SASS 变量,App.vue 管应用生命周期和全局样式,pages.json 管页面路径、窗口和 tabBar 等配置。

怎么做:在 uni.scss 中定义变量,运行时它会自动注入页面样式:

css
/* uni.scss */
/* 在原有 sass 变量基础上添加新的变量 */
$uni-bg-color: #f4f4f4;

随后在页面样式中使用该变量。转写稿里的调试过程是:定义变量后给 page 设置背景色,第一次发现颜色没生效,重新启动/刷新服务后才看到变化;这说明变量本身可用,问题多在编译服务未及时更新。第一次使用 SASS 时,HBuilderX 会提示安装 dart-sass 插件。

dart-sass插件

易错点:uni.scss 是变量和全局 SASS 能力,不是普通 CSS 文件;页面使用 SASS 变量时样式块要支持 SCSS。

2.1.2 App.vue:不是根组件,而是应用入口 ​

为什么需要:小程序的 app.js 负责应用生命周期,app.wxss 负责全局样式。uni-app 的 App.vue 承接这两件事。

怎么想:script 对应 app.js,style 对应 app.wxss,template 必须省略。

怎么做:

html
<script>
  // 相当于小程序的 app.js
  export default {
    onLaunch: function () {
      console.log('App Launch')
    },
    onShow: function () {
      console.log('App Show')
    },
    onHide: function () {
      console.log('App Hide')
    },
  }
</script>

<!-- 组件模板需要被省略 -->
<template></template>
<!-- 组件模板需要被省略 -->

<style>
  /* 相当于 app.wxss */
  page {
    background-color: $uni-bg-color;
  }
</style>

转写稿中通过给 App.vue 的 style 写全局样式,再在首页放一个元素验证文字颜色变化,确认全局样式生效。

易错点:不要把 App.vue 当普通根组件写 template;应用级生命周期写在这里。

2.1.3 pages.json:页面配置与全局配置平级写 ​

为什么需要:小程序 app.json 同时管页面路径、窗口样式、tabBar、分包等。uni-app 用 pages.json 统一管理。

怎么想:pages 是页面配置,globalStyle 对应全局 window;其它全局配置如 tabBar、subPackages 与 globalStyle 平级。

怎么做:

json
{
	"pages": [
		{
			"path": "pages/index/index",
			"style": {
				"navigationBarTitleText": "学习uni-app"
			}
		}
	],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uni-app",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	},
	"uniIdRouter": {}
}

tabBar 配置示例:

json
{
	"pages": [],
	"globalStyle": {},
  "tabBar": {
    "color": "",
    "selectedColor": "",
    "borderStyle": "",
    "position": "",
    "list": [
      {
        "text": "",
        "pagePath": "",
        "iconPath": "",
        "selectedIconPath": ""
      }
    ]
  },
	"uniIdRouter": {}
}

subPackages 配置示例:

json
{
	"pages": [],
	"globalStyle": {},
  "tabBar": {},
  "subPackages": [
    {
      "root": "",
      "pages": [
        {
          "path": "",
          "style": {
            
          }
        }
      ],
    }
  ],
	"uniIdRouter": {}
}

易错点:tabBar 图片必须放 static 目录,否则小程序端可能无法运行;不要把这些全局项误写进 globalStyle 内部。

2.2 组件:内置组件照小程序,扩展组件按需下载 ​

为什么需要:跨端要尽量表现一致。uni-app 重新实现了微信小程序内置组件,所以会小程序组件就能迁移。

怎么做:

xml
<view class="message">hello uni-app!</view>
<image src="" mode="" />
<swiper autoplay>
  <swiper-item>
  	<image src="" />
  </swiper-item>
  <swiper-item>
  	<image src="" />
  </swiper-item>
<swiper>

扩展组件(uni ui)偏业务交互,如倒计时、日历、文件上传,需要下载到项目中再按文档使用。

uni ui

易错点:扩展组件不是内置即用;插件市场第三方库要注意 Vue3 兼容性,例如 uView 不支持 Vue3。

2.3 生命周期:应用/页面用小程序,组件用 Vue ​

为什么需要:uni-app 同时存在小程序生命周期和 Vue 生命周期,混用会写错位置。

怎么想:记原则——应用生命周期、页面生命周期采用小程序;自定义组件生命周期使用 Vue。Vue3 setup 中,应用/页面生命周期要从 @dcloudio/uni-app 引入。

html
<script setup>
  // Vue 组件生命周期
  import { onMounted } from 'vue'
  // 应用/页面生命周期(小程序生命周期)
  import { onLaunch, onLoad } from '@dcloudio/uni-app'
  
  // ...
</script>

易错点:onLoad、onShow 等页面生命周期不要从 vue 引入;应用级 onLaunch 应放在 App.vue 逻辑中。

2.4 API 调用:命名空间换成 uni,回调与 Promise 二选一 ​

为什么需要:小程序 API 常以 wx. 调用,uni-app 为跨端统一改为 uni.。

怎么做:

html
<script setup>
  import { onLoad } from '@dcloudio/uni-app'
  
  // 页面加载后获取接口数据
  onLoad(() => {
    // 原来的 wx.request 换成 uni.request
    uni.request({
      url: '',
      success(result) {
        console.log(result)
      }
    })
  })
</script>

Promise 规则:传入 success、fail、complete 任一回调,就是 callback 方式,不返回 Promise;不传回调则返回 Promise。

javascript
// 回调方式,不返回 Promise
uni.request({
  url: 'https://your.api.com/xxx',
  success: (result) => {
    console.log(result)
  }
})

// 如果在调用 API 时传入了 success fail complete 那么不会返回 Promise
javascript
// Promise 方式
const result = uni.request({
  url: 'https://your.api.com/xxx'
})
// Promise 对象
console.log(result)

易错点:不要一边传 success 一边又 await 返回值;Promise 方式便于配合 async/await。

2.5 条件编译:一套代码里给不同平台留口子 ​

为什么需要:跨端有差异,例如 uni.login 在 H5 不支持,keep-alive 只用于 H5。条件编译让特定代码只在指定平台参与编译。

怎么做:用特殊注释标记:

#ifdef 平台名称 || 平台名称
特定平台要执行的代码
#endif

#ifndef 平台名称
除了特定平台之外其它平台要执行的代码
#endif

示例:

html
<script setup>
  // #ifdef H5
  console.log('这段代码只在 H5 端才会运行')
  // #endif
</script>
<template>
  <!-- #ifdef H5 -->
  <view class="iconfont icon-search"></view>
  <!-- #endif -->
  
  <!-- #ifndef H5 -->
  <view class="iconfont icon-scan"></view>
  <!-- #endif -->
</template>
<style lang="scss" scoped>
  .iconfont {
    color: #666;
    font-size: 30rpx;
    /* #ifdef H5 */
    font-size: 28rpx;
    /* #endif */
  }
</style>

常用平台名有 VUE3、APP-PLUS、APP-ANDROID、APP-IOS、H5、MP、MP-WEIXIN、MP-ALIPAY。

易错点:条件编译靠注释识别,注释符号和 #ifdef/#endif 不能写错;它是在编译阶段生效,不是运行时判断。

作业目标:把真机运行环境和 HBuilder 配置跑通 ​

本节作业不是写业务页面,而是把后续开发要用的环境与工具配置顺一遍:真机运行能连上、HBuilder 能装插件、Prettier 能格式化、没有安卓手机时知道用云手机验证。下面按课堂演示顺序整理。

一、真机运行失败时先排查环境 ​

为什么需要: 真机运行要在手机上安装 App,手机会弹出授权提示;不同手机型号界面有差异,连接也可能“上午好用、下午不好用”。
怎么想: 先判断是步骤问题还是环境问题。步骤上,看到授权提示必须点“允许”;环境上,按“撤销授权→拔插数据线→关开 USB 调试→重启手机”的顺序排查。
怎么做: 连接成功后,在手机弹窗中勾选允许,让电脑向手机安装 App。若之前授权过但失效,先撤销授权,拔掉数据线重新插上;再次弹出授权就点允许。还不行,把 USB 调试关一下再打开;仍不行就重启手机。苹果手机真机需要证书,课堂不要求购买;没有安卓手机也不影响学习,后面可用云手机验证。
易错点: 不要点拒绝;不要一失败就以为代码错,可能是网络、数据线、手机型号或硬件环境;模拟器配置比真机更复杂,不推荐作为首选。

二、HBuilder 安装插件:以 Prettier 为例 ​

为什么需要: 课堂从 VS Code 转到 HBuilder,很多地方不如 VS Code 顺手,需要装插件提升开发体验;后面云打包也要注册账号。
怎么想: 插件安装方法比某个插件本身更重要。先注册/登录账号,再通过“工具→插件安装”进入插件市场搜索安装。
怎么做: 打开 HBuilder,注册并登录账号;点“工具→插件安装”,可查看已安装插件;需要新插件时点“前往插件市场安装”,搜索 Prettier,登录后点安装,HBuilder 会自动打开并确认安装;安装后在“插件安装”里能看到。
易错点: 不登录账号安装会麻烦;不要只记住 Prettier,要掌握“搜索—安装—查看”的通用步骤;以后装 ESLint 等插件也是同样方式。

三、配置 Prettier 与 HBuilder 基本设置 ​

为什么需要: 团队代码风格要统一:缩进两个还是四个、要不要分号、单引号还是双引号,都应由项目配置决定。
怎么想: 先配 Prettier,再开“保存时自动格式化”。课堂特别提醒:如果一上来就开自动保存/自动格式化,代码写到一半有错时可能立刻报错,容易误判。
怎么做: 打开“工具→设置→插件配置”,给 Prettier 补上生效范围,例如 **/*.js 这类匹配项。然后在项目根目录新建 .prettierrc,写入常用配置:

json
{
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "singleQuote": true,
  "vueIndentScriptAndStyle": true
}

再到 HBuilder 常用设置里把制表符改为 2,勾选“使用空格代替制表符”,勾选“保存时自动格式化”和“折叠最后一行”。需要手动格式化时右键选择“重排”。
易错点: .prettierrc 必须放在项目根目录;第一次重排若弹窗,要选自己安装的 Prettier,不要选内置;字体项需要本机已安装字体,没装就用默认。

四、云手机与全局文件验证 ​

为什么需要: 没有安卓手机或苹果证书时,仍要看看 App 在手机上的效果;企业测试多机型也不可能每种都买。云手机就是在线连接真手机做测试,免费时长通常有限。
怎么想: 云手机不是模拟器,而是平台提供的真手机;上传打包好的 APK 后进入云手机安装测试。全局文件方面,uni.scss 定义的是全局 Sass 变量,App.vue 的 script 相当于小程序 app.js,style 相当于 app.wxss。
怎么做: 注册云手机账号,上传 APK,进入云手机安装并打开验证。uni.scss 末尾可定义变量:

scss
/* uni.scss 末尾:自定义样式变量 */
$bg-color: pink;

页面样式要加 lang="scss" 后才能使用变量:

vue
<style lang="scss">
page {
  background-color: $bg-color;
}
</style>

App.vue 可写全局样式验证:

vue
<style>
.ts {
  color: red;
}
</style>

易错点: App.vue 不要写 template;首次用 Sass,HBuilder 会提示安装 sass 插件;服务卡住时可重启服务或重新运行;云手机免费时间用完需付费。

代码示例 ​

示例 1:uni.scss + App.vue(全局变量与全局入口) ​

css
/* uni.scss —— 全局 SASS 变量,运行时会自动注入到每个页面的样式里 */
/* 在原有 sass 变量基础上添加新的变量 */
$uni-bg-color: #f4f4f4;
html
<!-- App.vue -->
<script>
  // 相当于小程序的 app.js
  export default {
    onLaunch: function () {
      console.log('App Launch')
    },
    onShow: function () {
      console.log('App Show')
    },
    onHide: function () {
      console.log('App Hide')
    },
  }
</script>

<!-- 组件模板需要被省略 -->
<template></template>
<!-- 组件模板需要被省略 -->

<style lang="scss">
  /* 相当于 app.wxss */
  page {
    background-color: $uni-bg-color;
  }
</style>

关键行与易错点

  • $uni-bg-color 定义在 uni.scss 中即可全局使用,无需在页面里 @import,这是 uni-app 运行时自动注入的效果。
  • App.vue 里的 template 必须省略(或写成空标签),它不是根组件,只承担两件事:script 对应小程序的 app.js(应用级生命周期),style 对应小程序的 app.wxss(全局样式)。
  • 使用 $uni-bg-color 时,<style> 必须加 lang="scss",否则变量不生效;首次加该属性 HBuilderX 会提示自动安装 dart-sass 插件,装完需重新运行。
  • 改动 uni.scss 后如果颜色没变化,先停掉再重新运行服务(转写稿中演示时正是因为旧服务卡住导致样式未生效)。

示例 2:pages.json(页面配置 + 全局配置) ​

json
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "学习uni-app"
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "uni-app",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8"
  },
  "tabBar": {
    "color": "",
    "selectedColor": "",
    "borderStyle": "",
    "position": "",
    "list": [
      {
        "text": "",
        "pagePath": "",
        "iconPath": "",
        "selectedIconPath": ""
      }
    ]
  },
  "subPackages": [
    {
      "root": "",
      "pages": [
        {
          "path": "",
          "style": {}
        }
      ]
    }
  ],
  "uniIdRouter": {}
}

关键行与易错点

  • pages 是页面配置:path 指定页面路径,style 是这一页自己的配置(导航栏标题、背景色等)。
  • globalStyle 是全局配置,对应小程序 app.json 里的 window。
  • 其余全局配置(tabBar、subPackages 等)与 globalStyle 平级书写,不要嵌套进 globalStyle 里面——这是最容易写错的地方。
  • 重点:tabBar 的图标图片必须放在 static 目录下,否则小程序端无法运行。
  • pages 数组的第一项就是启动页,新增页面必须先在 pages 中注册才能访问。

示例 3:页面中的生命周期 + API 调用 + 条件编译 ​

html
<script setup>
  // Vue 组件生命周期
  import { onMounted } from 'vue'
  // 应用/页面生命周期(小程序生命周期)
  import { onLoad } from '@dcloudio/uni-app'

  // 页面加载后获取接口数据
  onLoad(() => {
    // 原来的 wx.request 换成 uni.request
    uni.request({
      url: 'https://your.api.com/xxx',
      success: (result) => {
        console.log(result)
      }
    })
  })

  onMounted(() => {
    console.log('组件 mounted')
  })

  // #ifdef H5
  console.log('这段代码只在 H5 端才会运行')
  // #endif
</script>

<template>
  <!-- #ifdef H5 -->
  <view class="iconfont icon-search"></view>
  <!-- #endif -->

  <!-- #ifndef H5 -->
  <view class="iconfont icon-scan"></view>
  <!-- #endif -->
</template>

<style lang="scss" scoped>
  .iconfont {
    color: #666;
    font-size: 30rpx;
    /* #ifdef H5 */
    font-size: 28rpx;
    /* #endif */
  }
</style>

关键行与易错点

  • 生命周期分工原则:应用级(onLaunch/onShow/onHide)和页面级(onLoad/onShow/onHide/onReady)用小程序的生命周期,组件级用 Vue 生命周期。setup 语法下页面/应用生命周期要从 @dcloudio/uni-app 导入,不能从 vue 导入。
  • API 命名空间统一换成 uni:wx.request → uni.request,其余用法一致。
  • Promise 规则:调用时传了 success/fail/complete 任一回调就是 callback 方式、不返回 Promise;一个都不传才返回 Promise,可配合 async/await。
  • 条件编译是特殊注释,#ifdef 平台名 表示只在某平台编译,#ifndef 表示排除某平台;template、script、style 三处写法不同(HTML 用 <!-- -->,JS/CSS 用 /* */)。
  • 常见平台名:H5、MP-WEIXIN、MP-ALIPAY、APP-PLUS、APP-ANDROID、APP-IOS、VUE3;多个平台用 || 连接。

常见错误 ​

  1. 现象:tabBar 配置后小程序端不显示或直接运行失败 → 原因:iconPath、selectedIconPath 图片未放在 static 目录 → 修法:把 tabBar 图标统一移到 static 下,并修正 pages.json 中的路径。
  2. 现象:App.vue 编译报错或页面结构异常 → 原因:在 App.vue 中写了 <template> → 修法:删除 template,只保留 script 和 style。
  3. 现象:pages.json 中 tabBar、subPackages 不生效 → 原因:误把这些全局配置写进 globalStyle 内部 → 修法:将 tabBar、subPackages 与 globalStyle 平级配置。
  4. 现象:页面里写 onLaunch 不执行,或组件里写 onLoad 不执行 → 原因:应用/页面生命周期与 Vue 组件生命周期混用 → 修法:应用生命周期放 App.vue,页面生命周期放页面,组件用 Vue 生命周期;setup 中页面生命周期从 @dcloudio/uni-app 导入。
  5. 现象:调用 uni.request 后 await 拿不到预期结果 → 原因:同时传了 success/fail/complete 又按 Promise 方式使用 → 修法:二选一;要 await 就不要传回调,要回调就不要按 Promise 取返回值。
  6. 现象:条件编译代码在错误平台执行或完全不生效 → 原因:平台名写错、注释格式不规范、#ifdef/#ifndef 未闭合 → 修法:核对平台名称,按 // #ifdef H5、// #endif 规范书写,并检查成对闭合。
  7. 现象:uni.scss 中变量在页面样式里不可用 → 原因:style 未声明 lang="scss",或 Sass 插件未安装完成 → 修法:给对应 style 加 lang="scss",按提示安装 dart-sass 后重启服务验证。
  8. 现象:HBuilderX 中右键“重排”后格式化结果不符合预期 → 原因:首次弹窗选择了内置格式化器,或 Prettier 未按项目配置生效 → 修法:弹窗选择已安装的 Prettier;确认项目根目录存在 Prettier 配置文件,并检查插件配置中的生效范围。

练习 ​

  1. 在 uni.scss 中定义一个全局颜色变量,并在首页样式中通过 lang="scss" 使用它,验证变量是否全局生效。
  2. 配置一个包含 2 个页面的 tabBar,图标放到 static 目录,分别验证微信小程序端和 H5 端是否正常显示。
  3. 在 App.vue 中监听应用生命周期,在首页监听页面生命周期,在自定义组件中监听 Vue 生命周期,并说明各自执行时机。
  4. 使用 uni.request 分别写出 callback 写法和 Promise/async-await 写法,并验证“传回调不返回 Promise、不传回调返回 Promise”的差异。
  5. 使用条件编译,让同一段模板在 H5 显示搜索图标、非 H5 显示扫码图标,并检查编译结果。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1真机环境问题总结07:38
2HBuilder安装插件08:24
3HBuilder插件配置10:11
4HBuilder基本配置06:42
5答疑和HBuilder动手机测试09:57
6uni-app全局文件-uni.scss10:09
7uni-app全局文件-App.vue07:40

小结 ​

  1. uni.scss、App.vue、pages.json 是全局能力入口,但职责边界要分清,不能混写。
  2. App.vue 不是普通根组件,template 必须省略;应用生命周期和全局样式都从这里入手。
  3. pages.json 中只有 globalStyle 是全局窗口配置,其他全局配置要与它平级。
  4. 生命周期先按“应用/页面用小程序、组件用 Vue”判断,再考虑 setup 中的导入来源。
  5. uni.request 的 callback 与 Promise 是互斥使用方式,混用会导致返回值判断错误。
  6. 条件编译要严格依赖平台名称和注释语法,平台差异代码应尽量局部化。
  7. HBuilderX 的插件安装、Prettier 配置、保存自动格式化有顺序要求,先配格式化再开自动保存可减少误报。