因为文章太长,所以把实战部分拆分到本节中~
0x0、布局实战:写个抠腚优鲜的首页
看那么多,总得练下手,随手找个小程序参(chao)考(xi)下吧,这里选择的是每日优鲜,利用上一节学到的姿势反编译一波,拿下图片素材。如果不知道如何反编译微信小程序,可自行查阅上一节:《我写小程序像菜虚鲲——2、鸡你太美》,反编译后的文件如下:

打开images文件夹,可以看到小程序里用到的一些图标:

试下把反编译后的项目导入到微信开发者工具中,设置记得关下域名检验

2333,这已经不算是开卷考试了,而是拿着参考答案来做题了,行吧,开始干活,实现下这个页面~
① 设置标题与底部tab选项卡
把标题设置为抠腚优鲜,打开app.json
进行如下配置:
"navigationBarTitleText": "抠腚优鲜",
接着是底部tab选项卡,关于tabBar的详细介绍可自行查阅官方文档:
developers.weixin.qq.com/miniprogram…
把反编译后的项目里的images目录直接拷贝到项目中,打开app.json
,添加下述配置:
"tabBar": {
"color": "#969696",
"selectedColor": "#ff4891",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/tab-bar-home.png",
"selectedIconPath": "images/tab-bar-home-active.png"
},
{
"pagePath": "pages/index/index",
"text": "赚钱",
"iconPath": "images/tab-bar-group-sign.png",
"selectedIconPath": "images/tab-bar-group-sign-active.png"
},
{
"pagePath": "pages/index/index",
"text": "分类",
"iconPath": "images/tab-bar-category.png",
"selectedIconPath": "images/tab-bar-category-active.png"
},
{
"pagePath": "pages/index/index",
"text": "购物车",
"iconPath": "images/tab-bar-cart.png",
"selectedIconPath": "images/tab-bar-cart-active.png"
},
{
"pagePath": "pages/index/index",
"text": "我的",
"iconPath": "images/tab-bar-mine.png",
"selectedIconPath": "images/tab-bar-mine-active.png"
}
]
},
接着运行看下效果:

② 页面区域划分
写界面之前先划分一下区域,如图,划分成六个:

- ① 顶部栏:定位部分 + 搜索部分
- ② Banner轮播图
- ③ 新人福利
- ④ 信息标签
- ⑤ 商品分类
- ⑥ 悬浮提醒
划分完,接着一个个来实现~
③ 顶部栏
页面结构如下:
<!-- index.wxml -->
<view class="container">
<!-- 顶部栏 -->
<view class="top-wrapper">
<!-- 定位部分 -->
<view class="location_box">
<image class="location_icon" src="{{yx.location_icon_url}}"></image>
<image class="express_icon" src="{{yx.express_icon_url}}"></image>
</view>
<!-- 搜索部分 -->
<view class="search-wrapper">
<image class="search_icon" src="{{yx.search_icon_url}}"></image>
<text class="search_text">搜索</text>
</view>
</view>
</view>
样式调整顺序如下:
- 定位图片宽高44rpx * 44rpx,快速图片宽高120rpx * 30rpx;
- 搜索字体大小28rxp,字体颜色#969696;
- 顶部栏宽度占满100%,高度88rpx,flex布局,space-between两端占满,垂直居中;
- 定位部分左侧偏移16rpx;
- 搜索部分,flex布局,宽高534rpx * 60rpx,圆角12rpx,背景颜色#f5f5f5,
Item水平居中,垂直居中;- 搜索部分右侧偏移16rpx;
- 搜索文字右侧偏移16rpx;
对应样式文件如下:
.top-wrapper {
display: flex;
width: 100%;
height: 88rpx;
align-items: center;
justify-content: space-between;
}
.location_box {
margin-left: 16rpx;
}
.location_icon {
width: 44rpx;
height: 44rpx;
}
.express_icon {
width: 120rpx;
height: 30rpx;
}
.search-wrapper {
display: flex;
width: 534rpx;
height: 60rpx;
border-radius: 12rpx;
background-color: #f5f5f5;
align-items: center;
justify-content: center;
margin-right: 16rpx;
}
.search_icon {
width: 26rpx;
height: 26rpx;
margin-right: 16rpx;
}
.search_text {
font-size: 28rpx;
color: #969696;
}
运行结果如下:

④ Banner轮播图
小程序提供了一个滑块视图容器swiper组件,利用它可以实现简单的轮播图。详细官方文档:
developers.weixin.qq.com/miniprogram…
页面结构如下:
<!-- Banner -->
<view class="banner-wrapper">
<!-- 轮播图部分 -->
<swiper class="banner-swiper">
<block wx:for="{{yx.banner_urls}}">
<swiper-item>
<image class="banner_image" src="{{item}}" mode="widthFix"></image>
</swiper-item>
</block>
</swiper>
<!-- 当前页数 -->
<view class="pagination">1/5</view>
</view>
样式调整顺序如下:
- 最外层view宽度100%;
- 轮播图swiper元素高度280rpx;
- 接口返回的轮播图是750px*448px的, 不做处理直接显示会显示不全,可通过裁剪或设置偏移来解决这个问题,每日优鲜采用的 向上负偏移来解决,即向上偏移:280rpx-448rpx=-168rpx。
- 页数使用绝对定位,距离底部15rpx,右侧20rpx,背景rgba(0, 0, 0, 0.3),圆角24rpx,字体白色#FFFFFF,大小24rpx,内边距8rpx 15rpx。
对应样式文件如下:
.banner-wrapper {
width: 100%;
position: relative;
}
.banner-swiper {
height: 280rpx;
}
.banner-item {
overflow: hidden;
display: block
}
.banner_image {
width: 100%;
margin-top: -168rpx;
}
.pagination {
position: absolute;
bottom: 15rpx;
right: 20rpx;
background: rgba(0, 0, 0, 0.3);
line-height: 1;
padding: 8rpx 15rpx;
border-radius: 24rpx;
color: #fff;
font-size: 24rpx;
}
运行结果如下:

不过现在只能手动滑切换图片,接着添加定时自动滑动和页数变化,swiper提供下面三个属性:
- autoplay:是否自动切换。
- interval:自动切换的时间间隔。
- duration:滑动动画时长。
添加上述属性到代码中:
<swiper class="banner-swiper" autoplay="true" interval="5000" duration="5000">
编译后可以看到图片已经能自动滚动了,接着绑定下页面切换的事件,当页面改变时切换右下角那个页数的显示,添加下述代码:
<!-- index.js -->
current: 1,
onPageChange: function(e) {
this.setData({
current: e.detail.current + 1
})
},
<!-- index.wxml -->
<swiper ..bindchange="onPageChange">
<view class="pagination">{{current}}/5</view>
运行结果如下:

⑤ 新人福利
页面结构如下:
<!-- 新人福利 -->
<view class="welfare">
<view class="welfare-container">
<!-- 顶部图片 -->
<image class="welfare-top-image" src="{{yx.welfare_top_url}}"></image>
<!-- 商品部分 -->
<view class="welfare-goods-container">
<block wx:for="{{yx.welfare_goods}}">
<view class="goods-wrapper">
<image class="goods-image" src="{{item.icon}}"></image>
<image class="goods-price" src="{{item.price}}"></image>
</view>
</block>
</view>
<!-- 底部图片 -->
<image class="welfare-bottom-image" src="{{yx.welfare_bottom_url}}"></image>
</view>
</view>
先把商品部分的标签注释掉,样式调整顺序如下:
- 最外层设置flex布局,主轴从上往下,item居中,背景白色,上下内间距24rpx;
- 外层设置flex布局,主轴从上往下,item居中,宽690rpx,高434rpx,圆角12rpx,背景颜色#d4545a;
- 顶部图片100%,高度110rpx,左上和右上圆角12rpx;
- 商品部分最外层设置flex布局,主轴从上往下,item居中;
- 商品部分外层宽度660rpx,高度212rpx,圆角12rpx,上下内间距12rpx,左右内间距20rpx;
- 底部图片宽660rpx,高96rpx,圆角12rpx;
对应样式文件如下:
.welfare {
display: flex;
flex-direction: column;
align-items: center;
background: #fff;
padding: 24rpx 0;
}
.welfare-container {
display: flex;
flex-direction:column;
align-items:center;
width: 690rpx;
height: 434rpx;
border-radius: 12rpx;
background: #d4545a;
}
.welfare-top-image {
width: 100%;
height: 110rpx;
border-radius: 12rpx 12rpx 0 0;
}
.welfare-goods {
display: flex;
flex-direction: column;
align-items: center;
}
.welfare-goods-container {
width: 660rpx;
height: 212rpx;
box-sizing: border-box;
border-radius: 12rpx;
background: #fff;
padding: 12rpx 20rpx;
}
.welfare-bottom-image{
width: 660rpx;
height: 96rpx;
border-radius: 12rpx;
}
运行结果如下:

接着去掉商品部分的标签注释,调整样式:
- 商品外层设置flex布局,主轴从上往下,item居中,宽度134rpx,高度100%;
- 商品图片宽高130rpx;
- 商品价格宽100%,高56rpx;
.goods-wrapper {
display: flex;
flex-direction: column;
align-items: center;
width: 134rpx;
height: 100%;
}
.goods-image {
width: 130rpx;
height: 130rpx;
}
.goods-price {
width: 100%;
height: 56rpx;
}

em…商品直接穿出来了,修改下商品外层布局flex布局,从左网友,两端占满:
.welfare-goods-container {
width: 660rpx;
height: 212rpx;
box-sizing: border-box;
border-radius: 12rpx;
background: #fff;
padding: 12rpx 20rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
}
运行结果如下:

⑥ 信息标签
页面结构如下:
<!-- 信息标签 -->
<view class="info-tag-container">
<block wx:for="{{yx.tag_info_list}}">
<view class="tag-wrapper">
<image class="tag-image" src="{{item.icon}}"></image>
<view class="tag-text">{{item.text}}</view>
</view>
</block>
</view>
样式调整顺序如下:
- 最外层高度48rpx,flex布局,两端对齐留白;
- 外层flex布局,内容居中;
- 标签图片宽高24rpx,右侧偏离8rpx;
- 标签字体颜色#ff4891,大小22rpx;
对应样式文件如下:
.info-tag-container {
height: 48rpx;
display: flex;
justify-content: space-around;
}
.tag-wrapper {
align-items: center;
display: flex;
}
.tag-image {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
.tag-text {
font-size: 22rpx;
color: #ff4891;
}
运行结果如下:

⑥ 商品分类
这里的商品分类不止10个,滑动到右侧还有3个,可以用官方提供的scroll-view组件来实现,详细官方文档:
developers.weixin.qq.com/miniprogram…
scroll-view的用法也很简单:scroll-x横向滚动,scroll-y纵向滚动,说个小bug~
scroll-view本身的display:flex不生效,外层元素需要设置属性white-space: nowrap,内层元素需要设置属性display: inline-block,如果内层元素需要用到flex布局,可以设置属性display: inline-flex; 还有内层元素不可以用float浮动。
接着滑动部分的,一个简单的套路是:宽度写死 = 每个商品View的宽度 * 7,不过这种方法有点low。看了下每日优鲜的玩法,是把这里拆分成了两个部分,这里照葫芦画瓢实现一波。
页面结构如下:
<!-- 商品类别 -->
<view class="good_category_container">
<scroll-view scroll-x class="scroll-view">
<view class="category_first">
<block wx:for="{{yx.category_list_first}}" wx:key="key">
<view class="good_category">
<image class="category-image" src="{{item.icon}}"></image>
<view class="category-text">{{item.text}}</view>
</view>
</block>
</view>
<view class="category_second">
<block wx:for="{{yx.category_list_second}}" wx:key="key">
<view class="good_category">
<image class="category-image" src="{{item.icon}}"></image>
<view class="category-text">{{item.text}}</view>
</view>
</block>
</view>
</scroll-view>
</view>
样式调整顺序如下:
- 最外层宽度100%,设置white-space: nowrap;
- scroll-view设置最大高度360rpx;
- 左侧部分,宽度100%,inline-flex,自动换行;
- 右侧部分,高度384rpx,inline-flex,主轴从上往下;
- 分类外层,flex布局,水平竖直居中,主轴从上往下,宽150rpx,顶部偏移24rpx;
- 分类图标,宽高104rpx;
- 分类文本,高34rpx,行高34rpx让文本垂直居中,字体颜色#474245,大小24rpx,顶部偏移10rpx;
对应样式文件如下:
.good_category_container {
width: 100%;
white-space: nowrap;
}
.scroll-view {
max-height: 360rpx;
}
.category_first {
width: 100%;
display: inline-flex;
flex-wrap: wrap;
}
.category_second {
height: 384rpx;
display: inline-flex;
flex-direction: column;
flex-wrap: wrap;
}
.good_category {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 150rpx;
margin-top: 24rpx;
}
.category-image {
width: 104rpx;
height: 104rpx;
}
.category-text {
font-size: 24rpx;
color: #474245;
height: 34rpx;
line-height: 34rpx;
margin-top: 10rpx;
}
运行结果如下:

⑦ 悬浮提醒
这种悬浮在页面上,不会因为页面滚动而滚动的部分,可以使用固定定位来实现。
页面结构如下:
<!-- 浮动提醒 -->
<view class="tip-container">
<image class="tip-image" src="{{yx.tip_image_url}}"></image>
</view>
样式调整顺序如下:
- 外层容器设置绝对定位,宽98rpx,高130rpx,离右边28rpx,离底部40rpx;
- 图片设置宽高100%;
对应样式文件如下:
.tip-container {
position: fixed;
right: 28rpx;
bottom: 40rpx;
width: 98rpx;
height: 130rpx;
}
.tip-image{
width: 100%;
height: 100%;
}
运行结果如下:

⑧ 最终效果展示

Tips:真机预览时发现分类那里滑动时有滚动条,可以在wxss加入下述样式隐藏滚动条~
::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
}