主题
uni-app 基础与环境搭建(三)
本页对应 uni-app 基础与环境搭建,共 7 段视频,约 1 小时 17 分。
学习目标
- 能够依据
pages.json的subPackages配置分包,正确设置root与pages,创建分包页面并通过navigator跳转验证其可访问。 - 能够定位并修复分包页面路径配置错误(如重复写
root、页面路径误加.vue、新建页面误勾选主包路径等)导致的页面无法打开问题。 - 能够通过插件市场安装 uni-ui 扩展组件,并在页面中直接使用倒计时、日历等组件且无需全局注册。
- 能够按步骤在 uni-app 项目中集成 uView Plus(修改
main.js、uni.scss、App.vue并安装依赖),并验证按钮、日历等组件生效。 - 能够区分应用、页面、组件三类生命周期,在
App.vue、页面和自定义组件中选用正确生命周期;在组合式 API 中通过@dcloudio/uni-app引入并使用onLoad、onShow等小程序生命周期。 - 能够将原生小程序 API 的
wx命名空间替换为uni,并根据是否传入success/fail/complete回调判断和实现 Promise 调用,验证调用结果。
知识点
先看本节要解决的问题:静态资源目录必须放对
为什么需要:转写稿开头提到一个很典型的现象:H5 能跑,小程序跑不起来,图标没有出来。讲师排查后发现,图片没有放在 static 目录下,而是随手放进了别的目录。小程序打包时,非 static 目录里的静态资源不会被打进小程序目录,页面里自然找不到图片。
怎么想:先不要怀疑组件写法,先看资源路径和打包结果。H5 能显示、小程序不显示,往往不是“图片写错了”,而是“图片根本没被打包进去”。uni-app 对静态资源目录有约定,图片、图标这类不需要编译的资源应放在 static 下。
怎么做:把图片移动到项目已有的 static 目录中,然后按 static/xxx.png 这类路径引用。转写稿中讲师说“这个项目原本就有一个文件夹,就叫 static,所以你就把我发给你的图片直接放到这个里头,然后按这个路径来写”。改完后保存、重新编译,再看图标是否出现。
易错点:不要随便新建类似 assets、images 的目录放小程序端要用的静态图;不要以为 H5 能显示就代表小程序也能显示;路径不要写成 ./static 或 /static 混用,按项目实际写法统一。
分包配置写在 pages.json 里,和 globalStyle 平级
为什么需要:小程序开发中常做分包,目的是优化首次加载性能。原生小程序可以配置分包,uni-app 也可以配置。转写稿中讲师明确说,本节不追求实质业务分包,先把语法和原生小程序对齐。
怎么想:分包配置属于页面路由配置,不是写在某个页面里,而是写在 pages.json 中。找到 globalStyle,在它同级写 subPackages。subPackages 是数组,因为可以配置多个分包;每个分包是一个对象。
怎么做:先折叠 pages.json,看清层级,再在 globalStyle 同级加配置。每个分包至少要有 root 和 pages。root 指定分包根目录,pages 是该分包下的页面数组。示例按转写稿的命名习惯可写成:
json
{
"globalStyle": {
"navigationBarTextStyle": "black"
},
"subPackages": [
{
"root": "subpkg_task",
"pages": [
{
"path": "detail/detail",
"style": {
"navigationBarTitleText": "任务详情"
}
}
]
}
]
}易错点:subPackages 不要写到 globalStyle 里面;root 不要写 ./subpkg_task,也不要写 /subpkg_task,写目录名即可;pages 里的 path 不要重复写 root,否则会变成 subpkg_task/subpkg_task/detail/detail。
新建分包页面时,不要勾选“自动添加到主包”
为什么需要:在 HBuilderX 里右键新建页面时,工具默认可能把页面路径加到主包 pages 中。但我们现在建的是分包页面,如果勾选了,就会平白无故多一条主包路径,导致配置混乱。
怎么想:先判断“这个页面属于主包还是分包”。主包页面可以让工具自动加路径;分包页面则应手动写到对应分包的 pages 数组里。
怎么做:右键新建页面,取消“创建同名目录”之外的自动添加主包路径选项;页面名可写 detail,创建同名目录后得到 detail/detail.vue 这类结构。然后回到 pages.json,在分包 pages 中写 path: "detail/detail"。页面标题写在 style.navigationBarTitleText 中。
易错点:path 不要写 .vue 后缀;不要写到 detail/detail/detail;页面标题属于页面 style,不要写到分包对象外层。
用 navigator 验证分包是否能跳转
为什么需要:配置完不代表一定能打开。最直接的验证方式是在首页放一个跳转链接,能跳到分包页面,就说明分包配置成功。
怎么想:跳转路径要从项目根路径开始写,也就是以 / 开头,后面跟分包根目录、页面目录和页面名。转写稿中讲师用 navigator 组件验证。
怎么做:在首页写类似:
html
<navigator url="/subpkg_task/detail/detail">跳转到分包页面</navigator>保存后重新编译,点击链接测试。若页面能打开,说明 root、pages.path 和跳转地址三者一致。
易错点:转写稿中讲师踩过一个坑:root 已经指定了 subpkg_task,pages.path 里又写了一遍根目录,结果页面找不到。记住:root 写一次,path 只写根目录后面的页面路径。改完 pages.json 后如果没生效,重新编译或重启开发工具再验证。
先看现象:H5 能跑,小程序图标却不出来
为什么需要:同一个页面在 H5 正常,到小程序端静态图片丢失,说明问题不在业务逻辑,而在资源路径和打包规则。
怎么想:先怀疑图片路径,再检查图片所在目录是否会被小程序打包。转写稿里提到,图片如果随手放在 static 之外的目录,静态资源可能打包不进小程序目录,运行时自然找不到。
怎么做:把图片统一放到项目已有的 static 目录下,例如 /static/xxx.png,页面里按这个路径引用。
易错点:不要随便新建一个类似 static 的目录名;不要以为 H5 能看到就代表小程序也能看到。转写稿中的调试过程就是:改到 static 下、保存、回到小程序看图标是否出现。
分包配置要写在 pages.json,并与 globalStyle 平级
为什么需要:小程序做分包可以优化首次加载体积,uni-app 也支持分包配置。
怎么想:分包不是写在某个页面里,而是写在 pages.json 的全局配置中;它和 globalStyle 是平级关系。每个分包是一个对象,至少要有 root 和 pages。
怎么做:先折叠代码看清层级,再写 subPackages 数组:
json
{
"globalStyle": {
"navigationBarTextStyle": "black"
},
"subPackages": [
{
"root": "startPkg_task",
"pages": [
{
"path": "detail/detail",
"style": {
"navigationBarTitleText": "任务详情"
}
}
]
}
]
}易错点:subPackages 不要写到 globalStyle 里面;root 只写目录名,不写 ./ 或 /;每个分包页面路径最终要能拼成 root + path。
本节核心 bug:root 已指定,pages.path 不要再重复根目录
为什么需要:转写稿里页面打不开,排查后发现不是跳转组件的问题,而是分包页面路径写重了。
怎么想:分包对象已经写了 "root": "startPkg_task",那么 pages 里的 path 只需要写根目录下面的相对路径。
怎么做:正确写法是 "path": "detail/detail"。不要写成 "path": "startPkg_task/detail/detail"。
易错点:这是本节要记住的“坑”:根已经写过了,页面路径里就不要再补一层根。转写稿中重新编译后页面能出来,说明配置层级和路径修正后分包生效。
用 navigator 验证分包页面能否跳转
为什么需要:配置写完不代表真的可用,要验证分包页面能否被访问。
怎么想:在首页放一个 navigator,点击能跳到分包页面,就说明分包路径配置成功。
怎么做:
html
<navigator url="/startPkg_task/detail/detail">跳转到分包页面</navigator>保存后重新编译,点击测试。转写稿中还提到:如果页面没出来,可以先重新编译或重启 HBuilderX 再试。
易错点:url 要写绝对路径,以 / 开头;路径写到页面名即可,不要写 .vue;不要因为编辑器偶尔提示“找不着”就慌,先看编译结果和实际跳转。
新建分包页面时,别让它自动注册到主包
为什么需要:分包页面属于分包,不应该再往主包 pages 里平白增加路径。
怎么想:新建页面时如果勾选了自动注册相关选项,HBuilderX 可能把路径加到主包配置里,这个路径你并不需要。
怎么做:新建分包页面时把自动注册到主包的选项去掉;如果需要同名目录,可以按需勾选“创建同名目录”。
易错点:主包页面和分包页面的新建策略不同;分包页面配置只写在对应分包的 pages 中。
小结
本节要记两句话:静态资源优先放 static 目录;分包配置中 root 已经指定后,pages.path 不要再重复根目录。前者解决图片在小程序端丢失,后者解决分包页面路径写重导致打不开的问题。
扩展组件要解决什么问题
为什么需要:原生小程序和 uni-app 内置组件能覆盖基础展示与跳转,但倒计时、弹层、日历这类交互组件通常没有现成内置件。转写稿明确说:“倒计时原生小程序有没有倒计时的组件?是不是没有?”这时就要借助组件库。
怎么想:uni-app 官方提供了 uni-ui,角色类似 Web 端的组件库,但专门用于 uni-app;它的优势是跨端兼容,打包到 H5、各小程序时更稳。
怎么做:把 uni-ui 当插件安装,安装后项目里会出现 uni_modules 目录。转写稿演示:“在项目当中就会多一个文件夹……里头放的就是扩展的组件。”
易错点:不要以为装完还要像 Vue 项目那样全局注册;转写稿强调 uni-ui“直接安装完就可以来用”。另外,转写稿里的“优你UI”应纠正为 uni-ui,“UF/UOF/UD”应理解为 uni-app。
安装 uni-ui 并直接使用
为什么需要:扩展组件不是复制一段标签就能跑,必须先让组件代码进入项目。
怎么想:按插件市场 → HBuilderX 安装的路径走;安装成功后看 uni_modules 是否出现。
怎么做:登录插件市场,点“打开 HBuilderX”,确定安装;然后在文档里复制示例。转写稿演示倒计时和日历时说:“基本上就是复制粘贴,然后再去修改。”
易错点:不要死记参数。转写稿说 day 是天数、小时/分钟/秒对应倒计时单位,“参数相对还是比较直观的”;日历等组件也应以文档为准。使用前确认 uni_modules 已生成,否则标签不会生效。
整合 uView Plus 的配置思路
为什么需要:uni-ui 稳定,但有些项目希望组件效果和文档更丰富,转写稿又演示了 uView Plus。它“基于 uView2 修改的 Vue3 版本”,支持 Vue3。
怎么想:既然项目是 HBuilderX 创建的 Vue3 项目,就选插件市场安装方式;不要选成 Vue2。转写稿提醒:“很多同学在选项目的时候都选成二了,一定要注意,我们是拿着 Vue3 来学习。”
怎么做:新建 Vue3 项目,插件市场安装 uView Plus;按文档完成四行代码和两个模块:main.js 加两行、uni.scss 引入变量文件、App.vue 加全局样式并让 style 使用 lang="scss",再按文档安装所需依赖。转写稿总结:“总共我们就加了四行代码,安装了两个模块。”
易错点:转写稿里的“HBU点”是 HBuilderX,“闷点GS”是 main.js,“unicus/unic萨斯”是 uni.scss,“ABD点6/APP点vi”是 App.vue。配置后建议重启 HBuilderX;App.vue 里写的样式是全局样式,不要误以为只影响当前页面。
用按钮和日历验证组件是否生效
为什么需要:配置对不对,不能只看文档,要跑起来验证。
怎么想:先用最简单的 <u-button> 验证组件注册和样式,再用日历验证复杂组件。
怎么做:页面中写示意代码:
html
<u-button type="success" loading loading-text="加载中">
按钮
</u-button>
<u-calendar :show="true" />转写稿调试时先出现“光秃秃”的按钮,加上 type="success" 后才出现 success 样式;加 loading 后出现小 loading,证明组件已生效。日历通过 show 控制显示。
易错点:标签不显示样式时,先查是否安装成功、是否按文档配置、是否重启编辑器;不要一上来怀疑跨端。转写稿还提到静态资源目录问题:图片应放 static 下,否则打包到小程序目录时可能找不到——这是同类“路径/目录”坑,配置组件时也要按官方目录约定走。
代码示例
1. pages.json:配置分包 + tabBar 静态资源路径
json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/mine/mine",
"style": {
"navigationBarTitleText": "我的"
}
}
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-active.png"
},
{
"pagePath": "pages/mine/mine",
"text": "我的",
"iconPath": "static/tabbar/mine.png",
"selectedIconPath": "static/tabbar/mine-active.png"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"subPackages": [
{
"root": "sub_pkg_task",
"pages": [
{
"path": "detail",
"style": {
"navigationBarTitleText": "任务详情"
}
}
]
}
]
}关键行 / 易错点
subPackages必须和globalStyle平级(同一个对象层级),不是塞在globalStyle里面。subPackages是数组,每个元素是一个分包对象,每个分包必须有root和pages两个字段。root直接写目录名sub_pkg_task,不要写./、也不要写/。pages里的path不要再重复写root那一层,也不要写.vue后缀,写到detail为止(写成sub_pkg_task/detail/detail就会找不到文件——这是课上踩的坑)。style里配的是页面级配置,页面标题用navigationBarTitleText,别写到外面去。- tabBar 图标路径必须以
/static/...或static/...开头,图片必须放在static目录下,随便建个别的目录(比如images)H5 能跑,但打包到小程序时静态资源不会被打进去,图标就永远出不来。 - 用 HBuilderX 新建分包页面时,不要勾选“在 pages.json 中注册”,否则它会在主包
pages里平白多出一条路径;主包页面才需要勾。
2. pages/index/index.vue:跳转分包页面 + 使用 uni-ui 扩展组件
vue
<template>
<view class="content">
<!-- 跳转到分包页面:url 以 / 开头,从项目根目录写起 -->
<navigator url="/sub_pkg_task/detail/detail">跳转到分包页面</navigator>
<!-- uni-ui 倒计时组件:day/hour/minute/second 都是数字,用 : 绑定 -->
<uni-countdown :day="1" :hour="2" :minute="30" :second="0" />
<!-- uni-ui 日历组件:show 为 true 时才显示 -->
<uni-calendar :show="true" />
</view>
</template>
<style>
.content {
padding: 30rpx;
}
</style>关键行 / 易错点
navigator是内置组件,用法和小程序原生一致;url以/开头表示项目根目录,所以完整写成/sub_pkg_task/detail/detail。- 在 HBuilderX 里写组件名时先敲
u,再敲组件名(如navi),会自动弹出提示,不用死记。 uni-countdown、uni-calendar属于 uni-ui 扩展组件:先在插件市场点“下载插件并导入 HBuilderX”,安装后项目里会多出uni_modules目录,之后直接使用即可,不需要像 Vue 那样全局注册。- 装完 uni-ui 后若页面打不开,重新编译/重启一次 HBuilderX 再看。
- 组件属性必须用
:绑定数字或布尔值(:day="1"、:show="true"),写成day="1"是字符串,容易出问题。 - 组件库的用法、参数含义(day 是天数、hour 是小时、minute 是分钟、second 是秒)查文档即可,不用背;文档往下滚还能看到效果预览。
3. sub_pkg_task/detail/detail.vue:组合式 API 下的生命周期与 API 调用
vue
<template>
<view class="detail">
<text>{{ title }}</text>
</view>
</template>
<script setup>
import { ref } from 'vue'
// 小程序生命周期不能从 vue 引入,必须从 @dcloudio/uni-app 引入
import { onLoad, onShow } from '@dcloudio/uni-app'
const title = ref('任务详情')
onLoad((options) => {
console.log('页面加载了...', options)
// 不传 success/fail/complete,就会返回 Promise,可以 .then
uni.request({
url: 'https://example.com/api/task/list'
}).then((res) => {
console.log('Promise 方式拿到结果', res)
})
// 传了 success 回调,就不会再返回 Promise
uni.request({
url: 'https://example.com/api/task/list',
success: (res) => {
console.log('success 回调', res)
}
})
})
onShow(() => {
console.log('页面显示了...')
})
</script>
<style>
.detail {
padding: 30rpx;
}
</style>关键行 / 易错点
onLoad/onShow是小程序页面生命周期,Vue 里根本没有,所以必须import { onLoad, onShow } from '@dcloudio/uni-app',不能从vue引入(从 vue 引入直接报错/不执行)。- 生命周期选用原则:应用级用小程序生命周期(
onLaunch/onShow/onHide,写在App.vue里)、页面级用小程序生命周期(onLoad/onShow/onReady)、自定义组件用 Vue 生命周期(onMounted等)。 - API 调用只需把命名空间从
wx.换成uni.(wx.request→uni.request、wx.showLoading→uni.showLoading),用法完全一致。 - 想用
.then拿结果,就不要传success/fail/complete回调;一旦传了,返回值就不再是 Promise(课上console.log打出123还报“不是函数”就是这个原因)。原生小程序里也不是所有 API 都返回 Promise,而 uni-app 里全部都可以。 - 上面接口地址是示意地址,实际请换成课程提供的任务列表接口,且该接口需要登录才返回数据。
常见错误
- 现象:H5 图标正常,小程序端图标/图片不显示。原因:图片放在非
static目录,未被打包进小程序产物。修法:静态资源统一放static,按static/...路径引用后重新编译验证。 - 现象:分包页面配置后打不开或提示找不到文件。原因:
root已指定分包根目录,pages[].path又重复写了根目录前缀。修法:pages[].path只写相对分包根的页面路径,如detail/detail。 - 现象:新建分包页面后
pages.json多出无关主包路径或目录结构混乱。原因:新建页面时仍按主包方式勾选自动注册/同名目录。修法:建分包页面时取消自动注册相关选项,手动写入对应分包pages。 - 现象:
subPackages配置不生效或编译报错。原因:配置位置/层级写错。修法:确认subPackages与globalStyle同级,且为数组,每个分包包含root与pages。 - 现象:组合式 API 页面中直接写
onLoad报错或不执行。原因:Vue 不提供小程序页面生命周期。修法:页面/应用用小程序生命周期,组合式中从@dcloudio/uni-app引入onLoad、onShow等。 - 现象:
uni.request既传success又.then(),Promise 不生效或报错。原因:传入success/fail/complete后不返回 Promise。修法:需要 Promise/await时不要传回调;需要回调时不要按 Promise 链式写。
练习
- 把首页图标从非
static目录移到static,修正引用路径,分别验证 H5 与微信小程序端显示正常。 - 在
pages.json中配置subpkg_task分包,页面为detail/detail,标题为“任务详情”,用navigator跳转验证;检查pages[].path是否未重复写root。 - 在页面中用组合式 API 引入并使用
onLoad、onShow打印日志;再建一个组件,改用 Vue 生命周期验证差异。 - 用
uni.request请求任务列表,分别写 Promise 写法(不传success)和回调写法,对比返回结果与执行顺序。 - 按文档整合 uViewPlus:补
main.js、uni.scss、App.vue配置,安装依赖并重启,使用u-button和日历组件验证。
课堂画面






原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | uni-app配置分包 | 17:44 |
| 2 | 分包bug书写问题解释 | 01:29 |
| 3 | uni-app扩展组件 | 10:52 |
| 4 | uni-app中使用uViewPlus | 15:26 |
| 5 | uni-app中生命周期的用法-1 | 11:52 |
| 6 | uni-app中生命周期的用法-2 | 10:05 |
| 7 | uni-app中API的调用 | 09:33 |
小结
- 多端项目不能只看 H5 结果,静态资源与页面配置要以目标小程序打包产物为准。
- 分包配置的核心是分清“分包根”和“页面相对路径”,路径层级不要重复。
- 生命周期选择先判断宿主:应用、页面、组件分别按对应规则选,组合式页面需显式引入。
- uni-app API 统一用
uni命名空间;Promise 行为取决于是否传回调。 - 扩展组件优先选官方
uni-ui或明确支持 Vue3/多端的uViewPlus,并严格按文档完成整合。 - 新建分包页面时手动维护
pages.json更可控,不要依赖主包式自动注册。 - 遇到“配置看似正确但页面打不开/资源丢失”,先重新编译或重启,再检查产物目录与路径。