第1章 1.3 页面与路由:pages.json

📌 上一章我们创建了第一个 uniapp 项目,看到了那个"Hello World"跑了起来。但你有没有想过:这个页面是从哪来的?点击 tabBar 切换页面是什么原理?小程序里那些"页面"到底是怎么组织的?

这一章我们就来解决这些问题。学完你会发现:页面管理原来这么简单,就靠一个文件——pages.json


🎯 开场 3 分钟:为什么要学这个?

你有没有遇到过这些情况:

  • 新建了一个页面,但小程序里怎么都找不到它——因为没在 pages.json 里注册
  • 想加个底部 tabBar,但不知道怎么配——还是 pages.json 的活儿
  • 想自定义页面标题,结果改了 wxml 没用——得改 pages.json

pages.json 就像是剧院的节目单——告诉小程序:有哪些"页面"节目、每个节目长什么样、观众该怎么切换。

学完这章,你就能:
1. 自由添加/删除页面
2. 配置底部 tabBar
3. 自定\n\nSimple tech illustration expla\n\nAI comic creation scene, creat\n\n义页面标题和样式
4. 用 easycom 自动引入组件(省去一堆 import)


🧱 基础 25 分钟:核心概念

1. pages.json 在哪?

my-project/
├── pages/
│   ├── index/
│   │   └── index.vue      # 页面文件
│   └── list/
│       └── list.vue
├── static/
├── App.vue
├── main.js
└── pages.json             # ⭐ 就是这个文件

pages.json 在项目根目录,和 App.vuemain.js 平级。

2. pages 数组:注册页面

{
"pages": [
{
  "path": "pages/index/index",
  "style": {
    "navigationBarTitleText": "首页"
  }
},
{
  "path": "pages/list/list",
  "style": {
    "navigationBarTitleText": "列表页"
  }
}
]
}

解释一下:
- path:页面路径,注意不要写文件后缀pages/index/index 而不是 pages/index/index.vue
- style:页面样式配置
- navigationBarTitleText:页面顶部的标题

💡 小明的购物清单类比:想象你在整理一叠便签纸。pages 数组就是便签纸清单,告诉小程序"我有这几张便签,按这个顺序排好"。

3. 新建页面的正确姿势

错误做法:直接在 pages/ 下新建文件

正确做法:两步走

Step 1:在 pages/ 下创建文件夹和 .vue 文件

pages/
└── mine/
└── mine.vue

Step 2:在 pages.jsonpages 数组里注册

{
"pages": [
{
  "path": "pages/index/index",
  "style": {
    "navigationBarTitleText": "首页"
  }
},
{
  "path": "pages/mine/mine",
  "style": {
    "navigationBarTitleText": "我的"
  }
}
]
}

⚠️ 注意!pages 数组里第一个页面是小程序的启动页。小程序打开默认显示它。

4. tabBar 配置:底部导航

想加个底部 tabBar(比如微信底部那种)?在 pages.json 加上 tabBar 节点:

{
"pages": [
{
  "path": "pages/index/index",
  "style": {
    "navigationBarTitleText": "首页"
  }
},
{
  "path": "pages/list/list",
  "style": {
    "navigationBarTitleText": "列表页"
  }
},
{
  "path": "pages/mine/mine",
  "style": {
    "navigationBarTitleText": "我的"
  }
}
],
"tabBar": {
"color": "#999999",
"selectedColor": "#1890ff",
"backgroundColor": "#ffffff",
"list": [
  {
    "pagePath": "pages/index/index",
    "text": "首页",
    "iconPath": "static/tabbar/home.png",
    "selectedIconPath": "static/tabbar/home-active.png"
  },
  {
    "pagePath": "pages/list/list",
    "text": "列表",
    "iconPath": "static/tabbar/list.png",
    "selectedIconPath": "static/tabbar/list-active.png"
  },
  {
    "pagePath": "pages/mine/mine",
    "text": "我的",
    "iconPath": "static/tabbar/mine.png",
    "selectedIconPath": "static/tabbar/mine-active.png"
  }
]
}
}

每个 tab 项说明:

属性 作用
pagePath 点击后跳转的页面(必须在 pages 数组里)
text tab 上显示的文字
iconPath 未选中时的图标路径
selectedIconPath 选中时的图标路径

💡 类比:tabBar 就像餐厅的菜单卡片,每张卡片对应一个"节目"(页面),点击哪张就上哪道菜。

5. globalStyle:全局样式

如果每个页面都要写相同的导航栏样式,太麻烦了。用 globalStyle 统一设置:

{
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "我的小程序",
"navigationBarBackgroundColor": "#1890ff",
"backgroundColor": "#f5f5f5"
}
}

效果:所有页面默认使用这个导航栏样式,除非单个页面在 style 里覆盖它。

6. easycom:自动引入组件(超实用!)

以前用组件要手动 import

import myButton from '@/components/my-button/my-button.vue'
export default {
components: { myButton }
}

现在用 easycom自动引入,不用手动 import

pages.json 添加:

{
"easycom": {
"autoscan": true,
"custom": {
  "^my-(.*)": "@/components/my-$1/my-$1.vue"
}
}
}

然后直接在 wxml 里用:

<my-button type="primary">点我</my-button>

不用 import,不用注册,直接用!

💡 类比:easycom 就像快递自动签收——以前要自己跑去驿站取,现在快递员直接放你门口。


🔥 实战 35 分钟:3 个递进的小项目

项目 1:配置一个带 tabBar 的小页面(5 分钟)

目标:搭建一个"首页 + 列表 + 我的"三 tab 小程序

Step 1:创建 3 个页面文件

pages/index/index.vue:

<template>
<view class="container">
<text>这是首页</text>
</view>
</template>

<style>
.container {
padding: 20px;
}
</style>

pages/list/list.vue:

<template>
<view class="container">
<text>这是列表页</text>
</view>
</template>

<style>
.container {
padding: 20px;
}
</style>

pages/mine/mine.vue:

<template>
<view class="container">
<text>这是我的页面</text>
</view>
</template>

<style>
.container {
padding: 20px;
}
</style>

Step 2:配置 pages.json

{
"pages": [
{
  "path": "pages/index/index",
  "style": {
    "navigationBarTitleText": "首页"
  }
},
{
  "path": "pages/list/list",
  "style": {
    "navigationBarTitleText": "列表页"
  }
},
{
  "path": "pages/mine/mine",
  "style": {
    "navigationBarTitleText": "我的"
  }
}
],
"tabBar": {
"color": "#999999",
"selectedColor": "#1890ff",
"backgroundColor": "#ffffff",
"list": [
  {
    "pagePath": "pages/index/index",
    "text": "首页"
  },
  {
    "pagePath": "pages/list/list",
    "text": "列表"
  },
  {
    "pagePath": "pages/mine/mine",
    "text": "我的"
  }
]
},
"globalStyle": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
}

预期效果:底部有三个 tab,点击切换,顶部导航栏显示对应标题。


项目 2:给列表页加个标题(15 分钟)

需求:从 JSON 数据读取"小明的购物清单",展示在列表页

数据准备static/goods.json:

[
{ "id": 1, "name": "苹果", "price": 5.5 },
{ "id": 2, "name": "香蕉", "price": 3.2 },
{ "id": 3, "name": "橘子", "price": 4.0 }
]

列表页 pages/list/list.vue:

<template>
<view class="container">
<view class="title">小明的购物清单</view>
<view v-for="item in goodsList" :key="item.id" class="item">
  <text class="name">{{ item.name }}</text>
  <text class="price">¥{{ item.price }}</text>
</view>
</view>
</template>

<script>
export default {
data() {
return {
  goodsList: []
}
},
onLoad() {
uni.request({
  url: '/static/goods.json',
  success: (res) => {
    this.goodsList = res.data
  }
})
}
}
</script>

<style>
.container {
padding: 20px;
}
.title {
font-size: 18px;
font-weight: bold;
margin-bottom: 15px;
color: #333;
}
.item {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.name {
color: #333;
}
.price {
color: #ff6600;
}
</style>

效果:页面加载时从 JSON 文件读取数据,展示购物清单。

💡 这个例子里我们继续用"小明的购物清单"——就像上一章做的那样,现在给它加上页面展示。


项目 3:组合技——做一个带配置的待办清单(15 分钟)

需求
1. 首页显示"待办清单"(用 easycom 自动引入组件)
2. 页面标题显示当前日期
3. 列表页用 tabBar 切换

Step 1:创建自定义组件 components/todo-item/todo-item.vue

<template>
<view class="todo-item">
<text class="checkbox">{{ done ? '✅' : '⬜' }}</text>
<text class="content">{{ text }}</text>
</view>
</template>

<script>
export default {
props: {
text: String,
done: Boolean
}
}
</script>

<style>
.todo-item {
display: flex;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #eee;
}
.checkbox {
margin-right: 10px;
}
.content {
font-size: 16px;
}
</style>

Step 2:配置 easycom(在 pages.json 添加)

{
"easycom": {
"autoscan": true,
"custom": {
  "^todo-(.*)": "@/components/todo-$1/todo-$1.vue"
}
},
"pages": [ /* 保持之前的配置 */ ],
"tabBar": { /* 保持之前的配置 */ }
}

Step 3:首页用组件

pages/index/index.vue:

<template>
<view class="container">
<view class="header">
  <text class="date">{{ currentDate }}</text>
  <text class="subtitle">待办事项</text>
</view>
<todo-item v-for="item in todos" :key="item.id" :text="item.text" :done="item.done" />
</view>
</template>

<script>
export default {
data() {
return {
  currentDate: '',
  todos: [
    { id: 1, text: '完成 pages.json 作业', done: false },
    { id: 2, text: '复习 Vue 语法', done: true },
    { id: 3, text: '写一篇学习笔记', done: false }
  ]
}
},
onLoad() {
const now = new Date()
this.currentDate = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`
}
}
</script>

<style>
.container {
padding: 20px;
}
.header {
margin-bottom: 20px;
}
.date {
font-size: 14px;
color: #999;
}
.subtitle {
font-size: 22px;
font-weight: bold;
color: #333;
display: block;
margin-top: 5px;
}
</style>

预期输出

2026-6-26
待办事项
⬜ 完成 pages.json 作业
✅ 复习 Vue 语法
⬜ 写一篇学习笔记

一句话解释:通过 easycom 自动引入组件,减少 import 代码;通过 onLoad 生命周期获取当前日期。


💪 进阶 20 分钟:常见坑 + 性能小贴士

坑 1:页面路径写了文件后缀

❌ 错误:

"path": "pages/index/index.vue"

✅ 正确:

"path": "pages/index/index"

⚠️ 路径不要写 .vue 后缀!小程序平台会报错"页面不存在"。


坑 2:tabBar 页面没在 pages 数组里

❌ 错误:tabBar.list 引用了 pages/mine/mine,但 pages 数组里没有它

✅ 正确:所有 tabBar 页面必须先在 pages 数组注册


坑 3:第一个页面不是想要的启动页

❌ 意外:本来想先显示"列表页",但 pages 数组第一个是"首页"

✅ 正确:调整 pages 数组顺序,第一个就是启动页


坑 4:easycom 规则写错了正则

❌ 错误:

"^my-(.*)": "@/components/my-$1/my-$1.vue"

写成了 my*$1 位置不对

✅ 正确:正则的捕获组 (.*) 要对应 $1,且路径要完整


坑 5:修改 pages.json 后没重新编译

❌ 错误:改了配置,但模拟器显示还是旧的

✅ 正确:保存文件后重新编译(HBuilderX 会自动热更新,但有时候需要手动停止再运行)


性能小贴士:tabBar 图标别太大

tabBar 图标建议 81x81 像素,格式用 png。图标太大会影响加载速度。


调试技巧:看控制台报错

打开 HBuilderX 的控制台面板,页面路由相关的报错会显示"页面不存在"或"页面注册冲突"。结合报错信息和 pages.json 配置排查,一般 2 分钟内能找到问题。


✏️ 练习题 + 作业题

练习题(10 分钟)

练习 1(2 分钟):改标题
- 输入:把 pages/index/index 的页面标题改成"欢迎来到首页"
- 预期输出:顶部导航栏显示"欢迎来到首页"
- 提示:改 pages.json 里对应页面的 navigationBarTitleText

练习 2(2 分钟):加一个 tab
- 输入:在现有 tabBar 里加一个"设置"tab,页面路径 pages/settings/settings
- 预期输出:底部 tab 多了一个"设置"项
- 提示:需要两步——创建页面文件 + 在 pagestabBar.list 里注册

练习 3(2 分钟):改全局背景色
- 输入:把 globalStyle.backgroundColor 改成 #f0f8ff
- 预期输出:所有页面背景变成浅蓝色
- 提示:在 globalStyle 节点下添加或修改 backgroundColor

练习 4(3 分钟):easycom 规则推理
- 输入:写出匹配 my-button@/components/my-button/my-button.vue 的 easycom 规则
- 预期输出:能正确映射
- 提示:捕获组 (.*) 捕获的是"button",然后用 $1 拼路径

练习 5(1 分钟):找错
- 输入:下面这个 pages.json 有什么问题?

{
"pages": [
{ "path": "pages/index/index.vue" }
]
}
  • 预期输出:报错"页面不存在"
  • 提示:路径里多了 .vue 后缀

作业题(30 分钟 - 2 小时)

作业:做一个「小明的课堂表」小程序

需求描述
用 uniapp 做一个简单的课表展示工具,锻炼 pages.json 配置 + 页面跳转能力。

功能点
1. 底部 tabBar 有"课表"和"设置"两个 tab
2. 课表页显示周一到周五的课程(用 JSON 数据或写死在代码里)
3. 设置页有一个开关,可以切换"深色模式"(修改 globalStyle)

加分项
1. 用 easycom 引入自定义课程卡片组件
2. 课表数据放到 static 目录的 JSON 文件里,用 uni.request 读取

验收标准
- 能跑起来,tabBar 切换正常
- 课表页显示课程信息
- 切换深色模式后,页面主题颜色变化


📚 总结 + 资源

本文学了 3 个核心点:
1. pages.jsonpages 数组管理所有页面,第一个是启动页
2. tabBar 配置底部导航,引用的页面必须先注册
3. easycom 自动引入组件,省去手动 import

延伸学习资源:
- uniapp 官方文档 - pages.json 配置
- uniapp 官方文档 - tabBar 配置
- Vue3 文档 - 组件基础

互动钩子:

你在配置 tabBar 的时候踩过什么坑?是图标路径写错了,还是页面没注册?评论区聊聊,老粉优先回复!


📍 下一章我们要学习「Vue3 语法 + uniapp 组件」,学完你就能写出真正有交互的页面了——不只是展示数据,还能响应用户的点击、输入。敬请期待!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。