Skip to content

uni-app 基础与环境搭建(三) ​

本页对应 uni-app 基础与环境搭建,共 7 段视频,约 1 小时 17 分。

学习目标 ​

  1. 能够依据 pages.json 的 subPackages 配置分包,正确设置 root 与 pages,创建分包页面并通过 navigator 跳转验证其可访问。
  2. 能够定位并修复分包页面路径配置错误(如重复写 root、页面路径误加 .vue、新建页面误勾选主包路径等)导致的页面无法打开问题。
  3. 能够通过插件市场安装 uni-ui 扩展组件,并在页面中直接使用倒计时、日历等组件且无需全局注册。
  4. 能够按步骤在 uni-app 项目中集成 uView Plus(修改 main.js、uni.scss、App.vue 并安装依赖),并验证按钮、日历等组件生效。
  5. 能够区分应用、页面、组件三类生命周期,在 App.vue、页面和自定义组件中选用正确生命周期;在组合式 API 中通过 @dcloudio/uni-app 引入并使用 onLoad、onShow 等小程序生命周期。
  6. 能够将原生小程序 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 链式写。

练习 ​

  1. 把首页图标从非 static 目录移到 static,修正引用路径,分别验证 H5 与微信小程序端显示正常。
  2. 在 pages.json 中配置 subpkg_task 分包,页面为 detail/detail,标题为“任务详情”,用 navigator 跳转验证;检查 pages[].path 是否未重复写 root。
  3. 在页面中用组合式 API 引入并使用 onLoad、onShow 打印日志;再建一个组件,改用 Vue 生命周期验证差异。
  4. 用 uni.request 请求任务列表,分别写 Promise 写法(不传 success)和回调写法,对比返回结果与执行顺序。
  5. 按文档整合 uViewPlus:补 main.js、uni.scss、App.vue 配置,安装依赖并重启,使用 u-button 和日历组件验证。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1uni-app配置分包17:44
2分包bug书写问题解释01:29
3uni-app扩展组件10:52
4uni-app中使用uViewPlus15:26
5uni-app中生命周期的用法-111:52
6uni-app中生命周期的用法-210:05
7uni-app中API的调用09:33

小结 ​

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