#头条创作挑战赛#
三、home 首页
### 3.1 创建 home 分支
运行如下的命令,基于 master 分支在本地创建 home 子分支,用来开发和 home 首页相关的功能:
git checkout -b home

3.2 配置网络请求
由于平台的限制,小程序项目中 不支持 axios,而且原生的 wx.request()API 功能较为简单,不支持拦截器等全局定制的功能。因此,建议在 uni-app 项目中使用 @escook/request-miniprogram 第三方包发起网络数据请求
3.2.1 安装 @escook/request-miniprogram
在终端通过如下命令安装:
npm install @escook/request-miniprogram

安装成功后,根目录会自动出现如下目录:

3.2.1 配置网络请求
在项目的 main.js 入口文件中,进行如下配置:
// 导入 $http 对象
import {
$http
} from '@escook/request-miniprogram'
// 将$http挂在到uni顶级对象之上,方便全局调用
uni.$http = $http
// 配置请求根路径
$http.baseUrl = 'https://www.uinav.com'
// 请求开始前做一些事情
$http.beforeRequest = function(options) {
uni.showLoading({
title: '数据加载中...' // 展示loading效果
})
}
// 请求完成之后做一些事情
$http.afterRequest = function(options) {
uni.hideLoading() // 隐藏loading效果
}
3.3 轮播图区域
3.3.1 请求轮播图的数据
1. 实现步骤
- 在 data中定义轮播图的数组
- 在 onLoad生命周期函数中调用获取轮播图数据的方法
- 在 methods中定义获取轮播图数据的方法
2. 示例
export default {
/**
* 初始化数据
* */
data() {
return {
// 1. 轮播图的数据列表,默认为空数组
swiperList: [],
}
},
onLoad() {
// 2. 在小程序页面钢价在的时候,调用获取轮播图数据的方法
this.getSwiperList()
},
methods: {
// 3. 获取轮播图数据的方法
async getSwiperList() {
// 3.1 发起请求
const {
data: res
} = await uni.$http.get('/api/public/v1/home/swiperdata')
// 3.2 请求失败时执行
if (res.meta.status !== 200) {
return uni.showToast({
title: '数据请求失败!',
duration: 1500,
icon: 'none',
})
}
// 3.3 请求成功时为 data 中的数据赋值
this.swiperList = res.message
}
}
}
获取到的数据格式示例如下:
{
"message": [
{
"image_src": "https://api-hmugo-web.itheima.net/pyg/banner1.png",
"open_type": "navigate",
"goods_id": 129,
"navigator_url": "/pages/goods_detail/index?goods_id=129"
}
],
"meta": {
"msg": "获取成功",
"status": 200
}
}
参数说明如下:
|
参数名 |
类型 |
说明 |
|
image_src |
string |
图片路径 |
|
open_type |
string |
打开方式 |
|
goods_id |
number |
商品id |
|
navigator_url |
string |
导航链接 |
3.3.2 渲染轮播图的 UI 结构
1. 渲染 UI 结构
<template>
<view>
<!-- 轮播图区域 -->
<swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true">
<!-- 循环渲染轮播图的 item 项 -->
<swiper-item v-for="(item, index) in swiperList" :key="index">
<view class="swiper-item">
<!-- 动态绑定图片的src属性 -->
<image :src="item.image_src"></image>
</view>
</swiper-item>
</swiper>
</view>
</template>
2. 美化 UI 结构
<style lang="scss">
swiper {
height: 340rpx;
.swiper-item {
width: 100%;
height: 100%;
}
}
</style>
测试效果如下:

3.3.3 配置小程序分包
分包可以减少小程序首次启动时的加载时间
项目中,将 tabBar相关的 4 个页面放在主包,其他页面(如:商品详情页、商品列表页)放在分包
在 uni-app 项目中,配置分包的步骤如下:
- 在项目根目录中,创建分包的根目录,命名为 subpkg
- 在 pages.json 中,和 pages节点平级的位置声明 subPackages节点,用来定义分包相关的结构:
- { "subPackages" : [{ "root" : "subpkg" , "pages" : [] }]}
- 在 subpkg目录上新建页面

3.3.4 点击轮播图跳转到商品详情页
将 <swiper-item></swiper-item>节点内的view组件,改造为navigator导航组件,并动态绑定url属性的值:
- 原先的 UI 结构:
- <swiper-item v-for="(item, index) in swiperList" :key="index"><view class="swiper-item"><!-- 动态绑定图片的src属性 --><image :src="item.image_src"></image></view></swiper-item>
- 改造之后的 UI 结构:
- <swiper-item v-for="(item, index) in swiperList" :key="index"><!-- 指定对应的商品页面,传入对应的商品信息 --><navigator class="swiper-item" :url="'/subpkg/goods_detail/goods_detail?goods_id=' + item.goods_id + '&image_src=' + item.image_src"><!-- 动态绑定图片的src属性 --><image :src="item.image_src"></image></navigator></swiper-item>
- 在 goods_detail.vue 文件中,编写具体的逻辑:展示传入的商品信息
- <template><view><view>获取到 goods_id = {{goods_id}} 的商品</view><image :src="image_src" mode="scaleToFill" style="width: 100%;"></image></view></template> <script>export default {data() {return {goods_id: Number,image_src: String};},// options为进入页面时传入的所有参数的对象onLoad(options) {console.log(options)this.goods_id = options.goods_idconsole.log(this.goods_id)this.image_src = options.image_srcconsole.log(this.image_src)}}</script>
- 示例结果如下:

3.3.5 封装 uni.$showMsg()
当数据请求失败之后,经常需要调用 uni.showToast({ /* 配置对象 */ }) 方法来提示用户。此时可以在全局封装一个 uni.$showMsg() 方法,来简化 uni.showToast() 方法的调用
具体实现步骤如下:
- 在 main.js 中,为 uni对象挂在自定义的 $showMsg() 方法:
- /*** 封装展示消息提示的方法*/uni.$showMsg = function(title = '数据加载失败!', duration = 1500) {uni.showToast({title,duration,icon: 'none',})}
- 更改原先请求失败时提示消息的调用:
- // 3. 获取轮播图数据的方法async getSwiperList() {// 3.1 发起请求const { data: res } = await uni.$http.get('/api/public/v1/home/swiperdata')// 3.2 请求失败时执行if (res.meta.status !== 200) return uni.$showMsg()// 3.3 请求成功时为 data 中的数据赋值this.swiperList = res.message}
3.4 分类导航区域
3.4.1 获取分类导航的数据
1. 实现思路
- 在 data中定义轮播图的数组
- 在 onLoad生命周期函数中调用获取数据的方法
- 在 methods中定义获取数据的方法
2. 示例
<script>
export default {
data() {
return {
// 1. 分类导航的数据列表
navList: [],
};
},
onLoad() {
// 2. 在 onLoad 中调用获取数据的方法
this.getNavList()
},
methods: {
// 3. 在 methods 中定义获取数据的方法
async getNavList() {
const {
data: res
} = await uni.$http.get('/api/public/v1/home/catitems')
if (res.meta.status !== 200) return uni.$showMsg()
this.navList = res.message
}
}
}
</script>
3. 获取到的数据如下所示:
{
"message": [
{
"name": "分类",
"image_src": "https://api-hmugo-web.itheima.net/pyg/icon_index_nav_4@2x.png",
"open_type": "switchTab",
"navigator_url": "/pages/category/index"
},
{
"name": "秒杀拍",
"image_src": "https://api-hmugo-web.itheima.net/pyg/icon_index_nav_3@2x.png"
},
{
"name": "超市购",
"image_src": "https://api-hmugo-web.itheima.net/pyg/icon_index_nav_2@2x.png"
},
{
"name": "母婴品",
"image_src": "https://api-hmugo-web.itheima.net/pyg/icon_index_nav_1@2x.png"
}
],
"meta": {
"msg": "获取成功",
"status": 200
}
}
返回参数说明 :
|
参数名 |
类型 |
说明 |
|
name |
string |
标题名称 |
|
image_src |
string |
图片路径 |
3.4.2 渲染分类导航的 UI 结构
- 定义如下的 UI 结构
- <template><!-- 分类导航区域 --><view class="nav-list"><view class="nav-item" v-for="(item, i) in navList" :key="i"><image :src="item.image_src" class="nav-img"></image></view></view></template>
- 通过如下的样式美化页面结构:
- <style lang="scss">.nav-list {display: flex;justify-content: space-around;margin: 15px 0; .nav-img {width: 128rpx;height: 140rpx;}}</style>
- 测试效果如下:

3.4.3 点击第一项,切换到分类页面
- 为 nav-item 绑定点击事件处理函数:
- <!-- 分类导航区域 --><view class="nav-list"><view class="nav-item" v-for="(item, i) in navList" :key="i" @click="navClickHandler(item)"><image :src="item.image_src" class="nav-img"></image></view></view>
- 定义 nacClickHandler事件处理函数:
- <script>export default {methods: {// nav-item 项被点击时的事件处理函数navClickHandler(item) {// 判断点击的是哪个 navif (item.name == '分类') {uni.switchTab({url: '/pages/cate/cate'})}}}}</script>
4.5 楼层区域
4.5.1 获取楼层数据
1. 实现思路
- 在 data中定义轮播图的数组
- 在 onLoad生命周期函数中调用获取数据的方法
- 在 methods中定义获取数据的方法
2. 示例
<script>
export default {
data() {
return {
// 1. 楼层的数据列表
floorList: [],
};
},
onLoad() {
// 2. 调用获取楼层数据的方法
this.getFloorList()
},
methods: {
//
async getFloorList() {
const {
data: res
} = await uni.$http.get('/api/public/v1/home/floordata')
if (res.meta.status !== 200) uni.$showMsg()
this.floorList = res.message
}
}
}
</script>
3. 获取到的数据示例
{
"message": [
{
"floor_title": {
"name": "时尚女装",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor01_title.png"
},
"product_list": [
{
"name": "优质服饰",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor01_1@2x.png",
"image_width": "232",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=服饰"
},
{
"name": "春季热门",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor01_2@2x.png",
"image_width": "233",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=热"
},
{
"name": "爆款清仓",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor01_3@2x.png",
"image_width": "233",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=爆款"
},
{
"name": "倒春寒",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor01_4@2x.png",
"image_width": "233",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=春季"
},
{
"name": "怦然心动",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor01_5@2x.png",
"image_width": "233",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=心动"
}
]
},
{
"floor_title": {
"name": "户外活动",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor02_title.png"
},
"product_list": [
{
"name": "勇往直前",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor02_1@2x.png",
"image_width": "232",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=户外"
},
{
"name": "户外登山包",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor02_2@2x.png",
"image_width": "273",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=登山包"
},
{
"name": "超强手套",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor02_3@2x.png",
"image_width": "193",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=手套"
},
{
"name": "户外运动鞋",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor02_4@2x.png",
"image_width": "193",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=运动鞋"
},
{
"name": "冲锋衣系列",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor02_5@2x.png",
"image_width": "273",
"open_type": "navigate",
"navigator_url": "/pages/goods_list/index?query=冲锋衣"
}
]
},
{
"floor_title": {
"name": "箱包配饰",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor03_title.png"
},
"product_list": [
{
"name": "清新气质",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor03_1@2x.png",
"image_width": "232",
"open_type": "navigate",
"navigator_url": "/pages/goods_list?query=饰品"
},
{
"name": "复古胸针",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor03_2@2x.png",
"image_width": "263",
"open_type": "navigate",
"navigator_url": "/pages/goods_list?query=胸针"
},
{
"name": "韩版手链",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor03_3@2x.png",
"image_width": "203",
"open_type": "navigate",
"navigator_url": "/pages/goods_list?query=手链"
},
{
"name": "水晶项链",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor03_4@2x.png",
"image_width": "193",
"open_type": "navigate",
"navigator_url": "/pages/goods_list?query=水晶项链"
},
{
"name": "情侣表",
"image_src": "https://api-hmugo-web.itheima.net/pyg/pic_floor03_5@2x.png",
"image_width": "273",
"open_type": "navigate",
"navigator_url": "/pages/goods_list?query=情侣表"
}
]
}
],
"meta": {
"msg": "获取成功",
"status": 200
}
}
返回参数说明
|
参数名 |
类型 |
说明 |
|
floor_title |
string |
一级分类标题 |
|
product_list |
array |
一级分类内容 |
|
name |
string |
名称 |
|
image_src |
string |
图片路径 |
|
image_width |
string |
图片宽度 |
|
open_type |
string |
打开方式 |
|
navigator_url |
string |
跳转连接 |
3.5.2 渲染楼层的标题
- 定义如下的 UI 结构:
- <template><!-- 楼层区域 --><view class="floor-list"><!-- 楼层的 item 项 --><view class="floor-item" v-for="(item, i) in floorList" :key="i"><!-- 楼层标题 --><image :src="item.floor_title.image_src" class="floor-title"></image></view></view></template>
- 美化楼层标题的样式
- <style lang="scss">.floor-title {height: 60rpx;width: 100%;display: flex;}</style>
3.5.3 渲染楼层里的图片
- 定义楼层图片区域的UI结构:
- <template><!-- 楼层区域 --><view class="floor-list"><!-- 楼层的 item 项 --><view class="floor-item" v-for="(item, i) in floorList" :key="i"><!-- 楼层标题 --><image :src="item.floor_title.image_src" class="floor-title"></image><!-- 楼层图片区域 --><view class="floor-img-box"><!-- 左侧大图片的盒子 --><view class="left-img-box"><image :src="item.product_list[0].image_src":style="{width: item.product_list[0].image_width + 'rpx'}" mode="widthFix"></image></view><!-- 右侧的 4 个小图片盒子 --><view class="right-img-box"><view class="right-img-item" v-for="(item2, i2) in item.product_list" :key="i2" v-if="i2 !== 0"><image :src="item2.image_src" mode="widthFix" :style="{width: item2.image_width + 'rpx'}"></image></view></view></view></view></view></template>
- 美化楼层图片区域的样式:
- <style lang="scss">.floor-title {height: 60rpx;width: 100%;display: flex;} .right-img-box {display: flex;flex-wrap: wrap;justify-content: space-around;} .floor-img-box {display: flex;padding-left: 10rpx;}</style>
- 完整的测试效果如下:

3.5.4 点击楼层图片跳转到商品列表项
- 在 subpkg 分包中,新建 goods_list 页面
- 楼层数据请求成功之后,通过双层 forEach 循环,处理 URL 地址:
- <script>export default {methods: {// 3. 获取楼层列表数据async getFloorList() {const {data: res} = await uni.$http.get('/api/public/v1/home/floordata')if (res.meta.status !== 200) uni.$showMsg() // 通过双层 forEach 循环,处理 URL 地址res.message.forEach(floor => {floor.product_list.forEach(prod => {prod.url = '/subpkg/goods_list/goods_list?' + prod.navigator_url.split('?')[1]})}) this.floorList = res.message}}}</script>
- 将图片外层的 view 组件,改造为 navigator 组件,并动态绑定 url 属性的值:
- <template><!-- 楼层区域 --><view class="floor-list"><!-- 楼层的 item 项 --><view class="floor-item" v-for="(item, i) in floorList" :key="i"><!-- 楼层标题 --><image :src="item.floor_title.image_src" class="floor-title"></image><!-- 楼层图片区域 --><view class="floor-img-box"><!-- 左侧大图片的盒子 --><navigator class="left-img-box" :url="item.product_list[0].url"><image :src="item.product_list[0].image_src":style="{width: item.product_list[0].image_width + 'rpx'}" mode="widthFix"></image></navigator><!-- 右侧的 4 个小图片盒子 --><view class="right-img-box"><navigator class="right-img-item" v-for="(item2, i2) in item.product_list" :key="i2" v-if="i2 !== 0":url="item2.url"><image :src="item2.image_src" mode="widthFix" :style="{width: item2.image_width + 'rpx'}"></image></navigator></view></view></view></view></template>
- 测试效果如下:点击任意一个图片之后:

3.6 分支的合并与提交
- 将本地的home分支进行本地的commit提交:
- git add .git commit -m "完成了home首页的开发"
- 将本地的home分支推送到远程仓库进行保存:
- git push -u origin home
- 将本地的 home 分支合并到本地的 master 分支:
- git checkout mastergit merge home
- 删除本地的 home 分支
- git branch -d home