通过上面的效果图,本示例包含两个界面,第一个界面产品列表界面,包含头部Banner,中间的产品列表和底部的Bottom,第二个界面产品详情界面,包含顶部大图、横向滑动列表、商品列表和商品详情弹窗,接下来分别实现相应的界面:
首先我们要编写首界面的布局文件grid.wxml:
<swiper indicator-dots="{{indicatorDots}}"
autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" indicator-color='#dbdbdb' indicator-active-color='#00ae61'>
<block wx:for="{{imgUrls}}">
<swiper-item>
<image src="{{item.toppic}}" class="slide-image" bindtap='toBannerInfo' data-index='{{index}}' width="355" height="150"/>
swiper-item>
block>
swiper>
<view class="pro-body">
<text class='pro-title'>咖啡+祝福 即刻表心意text>
<view class='items-list' >
<block class='pro-item' wx:for="{{proList}}">
<view class='pro-bodydiv' bindtap='toProListInfo' data-index='{{index}}'>
<image class='pro-img' src='{{item.toppic}}'/>
<view class='pro-name'>{{item.name}}view>
view>
block>
view>
<view class='pro-bottom'>
<view>
<view bindtap='toProHistory'>
<image class='pro-pay' src='/images/img_pay.jpg'/>
view>
<text class='pro-history'>购买历史text>
view>
view>
view>
在该布局文件中,使用微信小程序swiper控件实现首页顶部轮播图,通过该控件的相关属性,设置轮播图自动播放,显示时间,角标颜色等属性信息。
编辑grid.wxss文件,用于设置grid.wxml中相关控件的属性信息。
swiper {
width: 100%;
height: 420rpx;
}
swiper image {
width: 100%;
height: 100%;
display: block;
}
.pro-body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
padding-top: 60rpx;
background: #f9f9f9;
}
.pro-title {
font-size: 30rpx;
color: #333333;
margin-left: 40rpx;
}
.items-list {
width: 100%;
display: flex;
flex-flow: row wrap;
align-content: flex-start;
overflow: hidden;
padding-left: 2%;
padding-right: 2%;
}
.pro-item {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.pro-bodydiv {
flex:0 0 44%;
height: 280rpx;
margin-top: 5%;
margin-left: 2%;
margin-right: 2%;
border-radius: 20rpx;
background: white;
text-align: center;
}
.pro-img {
left: 0px;
top: 0px;
width: 98%;
height: 220rpx;
margin-top: 3rpx;
border-radius: 20rpx
}
.pro-name {
font-size: 23rpx;
color: #666666;
position: relative;
width: 100%;
top: 5rpx;
align-content: center;
text-align: center;
}
.pro-bottom {
width: 100%;
height: 100%;
margin-top: 80rpx;
margin-bottom: 150rpx;
text-align: center;
}
.pro-pay {
width: 130rpx;
height: 130rpx;
margin-bottom: 10rpx;
}
.pro-history {
font-size: 33rpx;
color: #0ca862;
text-decoration: underline;
}
其中,为实现Grid布局需设置items-list属性值display: flex;flex-flow: row wrap; align-content: flex-start;
编辑grid.js用于控件的数据处理:
// pages/grid/grid.js
Page({
/**
* 页面的初始数据
*/
data: {
imgUrls: [
{
"toppic": "/images/img_bann1.jpg",
"name": "玩出我的夏天"
}, {
"toppic": "/images/img_bann2.jpg",
"name": "你真棒"
}, {
"toppic": "/images/img_bann3.jpg",
"name": "毕业季"
}, {
"toppic": "/images/img_bann4.jpg",
"name": "干杯"
}, {
"toppic": "/images/img_bann5.jpg",
"name": "求抱抱"
}, {
"toppic": "/images/img_bann6.jpg",
"name": "宝贝谢谢你"
}
],
indicatorDots: true,
autoplay: true,
interval: 5000,
duration: 1000,
proList:[
{
"toppic": "/images/img_bann1.jpg",
"name": "玩出我的夏天"
}, {
"toppic": "/images/img_bann2.jpg",
"name": "你真棒"
}, {
"toppic": "/images/img_bann3.jpg",
"name": "毕业季"
}, {
"toppic": "/images/img_bann4.jpg",
"name": "干杯"
}, {
"toppic": "/images/img_bann5.jpg",
"name": "求抱抱"
}, {
"toppic": "/images/img_bann6.jpg",
"name": "宝贝谢谢你"
}, {
"toppic": "/images/img_bann7.jpg",
"name": "有你真好"
}, {
"toppic": "/images/img_bann8.jpg",
"name": "宝贝 生快"
}, {
"toppic": "/images/img_bann9.jpg",
"name": "为你点赞"
}, {
"toppic": "/images/img_bann10.jpg",
"name": "休息一夏"
}
]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.getImgUrls();
},
getImgUrls: function () {
var self = this;
wx.request({
url: '你的服务器地址...',
method: "GET",
success(res) {
console.log(res)
self.setData({
// imgUrls: res.data.bannerList,
// proList: res.data.centerList,
// bottomItem: res.data.bottom
})
}
})
},
toBannerInfo: function (e) {
var index = e.currentTarget.dataset.index;
var imgUrls = this.data.imgUrls;
var name = imgUrls[index].name;
var toppic = imgUrls[index].toppic;
// wx.showToast({
// title: name + '',
// })
wx.navigateTo({
url: '/pages/gridinfo/gridinfo?name=' + name + '&toppic=' + toppic,
})
},
toProListInfo: function (e) {
var index = e.currentTarget.dataset.index;
var proList = this.data.proList;
var name = proList[index].name;
var toppic = proList[index].toppic;
// wx.showToast({
// title: name + '',
// })
wx.navigateTo({
url: '/pages/gridinfo/gridinfo?name=' + name + '&toppic=' + toppic,
})
},
toProHistory: function (e) {
wx.showToast({
title: '购买历史',
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
由于没有服务器相关数据,本示例使用了本地数据来实现,如果有网络数据可直接修改wx.request()方法中的url地址即可,其中
indicatorDots: true,
autoplay: true,
interval: 5000,
duration: 1000,
为顶部轮播图的相关属性信息,
wx.navigateTo({
url: '/pages/gridinfo/gridinfo?name=' + name + '&toppic=' + toppic,
})
为界面跳转,同时向gridinfo界面传递name和toppic参数。
至此,第一个界面首界面基本实现。
在Page目录下创建一个新的目录,命名为gridinfo,在该目录下创建一个Page,命名为gridinfo,编辑gridinfo.wxml布局文件,该布局标题为上个界面的商品名称,该布局文件包含一个顶部图片布局,横向图片列表布局,纵向的商品列表布局,悬浮的底部布局和商品详情的弹窗布局,布局文件如下:
--pages/gridinfo/gridinfo.wxml-->
<view class='pro-top'>
<image src='{{toppic}}'/>
view>
<view class='pro-mid'>
<scroll-view class='pro-scroll' scroll-x='true' style="white-space: nowrap; display: flex">
<block class='pro-lists' wx:for="{{proList}}">
<view class='pro-item' style='display: inline-block' bindtap='toProListInfo' data-index='{{index}}'>
<image class="{{item.showView?'pro-itempic_show':'pro-itempic_hide'}}" src='{{item.pic}}'/>
<icon class="{{item.showView?'pro-selectpic_show':'pro-selectpic_hide'}}" type='success' size='20' color='#03a964'/>
view>
block>
scroll-view>
view>
<view class='pro-selecttitle'><text>选择商品text>view>
<view class='pro-productlists'>
<view class='pro-productitem' wx:for="{{productList}}">
<image class='pro-productpic' bindtap='toProductInfo' data-index='{{index}}' src='{{item.pic}}'/>
<text class='pro-productname' bindtap='toProductInfo' data-index='{{index}}'>{{item.name}}text>
<text class='pro-productprice' bindtap='toProductInfo' data-index='{{index}}'>¥{{item.price}}text>
<image class='pro-productadd' src='/images/img_add.jpg' bindtap='toProductAdd' data-index='{{index}}'/>
view>
view>
<view class='pro-copyright'>
<view class='pro-copyrightitem'>
<text class='pro-copyrightmsg' bindtap='toCopyrightMsg'>使用须知text>
<text class='pro-copyrightprivate' bindtap='toCoprightPrivate'>隐私权政策text>
view>
view>
<view class='pro-bottominfo'>
<text class='pro-bottomprize'>0份礼品text>
<view class='pro-bottompriceinfo'>
<text class='pro-bottomprice'>¥text>
<text class='pro-bottomprice2'>0.00text>
view>
<view class='pro-bottompay' bindtap='toPayInfo'>
<text>购买text>
view>
view>
<view class="pro-dialog {{isShowDialog?'isDialogShow':'isDialogHide'}}" >
<view class='pro-dialogdiv'>
<view class='pro-dialog-topdiv'/>
<view class='pro-dialog-botdiv'/>
<view class='pro-dialog-content'>
<image class='pro-dialog-pic' src='{{dialogPic}}'/>
<image class='pro-dialog-close' src='/images/img_gridinfo_close.jpg' bindtap='toDialogClose'/>
<text class='pro-dailog-name'>{{dialogName}}text>
<text class='pro-dailog-price'>¥ {{dialogPrice}}text>
<view class='pro-dialog-line'>view>
<view class='pro-dialog-scroll'>
view>
view>
view>
view>
其中,横向布局通过scroll-view控件,设置scroll-x=’true’属性来实现,因为要实现点击横向布局中的Item自动切换顶部图片地址,且被点击的Item添加边框和选择按钮,此处通过
class="{{item.showView?'pro-itempic_show':'pro-itempic_hide'}}"
三元运算符实现两种布局属性的切换。
编辑gridinfo.wxss文件,用于设置布局文件的相关属性。
/* pages/gridinfo/gridinfo.wxss */
.pro-top {
width: 100%;
height: 330rpx;
margin: 0;
padding: 0;
text-align: center
}
.pro-top image {
width: 75%;
height: 100%;
border-radius: 20rpx;
}
.pro-mid {
width: 100%;
height: 110rpx;
padding: 0;
margin-top: 35rpx;
text-align: center;
}
.pro-scroll {
width: 92%;
height: 140rpx;
padding: 0;
margin-left: 4%;
}
.pro-item {
width: 180rpx;
height: 100%;
text-align: center;
}
.pro-itempic_show {
width: 164rpx;
height: 100rpx;
margin-top: 20rpx;
border-radius: 16rpx;
border: 3rpx solid #03a964;
}
.pro-itempic_hide {
width: 164rpx;
height: 100rpx;
margin-top: 20rpx;
border-radius: 16rpx;
border: 0;
}
.pro-selectpic_show {
position: absolute;
width: 40rpx;
height: 40rpx;
margin-left: 147rpx;
top: 10rpx;
display: block;
}
.pro-selectpic_hide {
position: absolute;
width: 40rpx;
height: 40rpx;
margin-left: 147rpx;
top: 10rpx;
display: none;
}
.pro-selecttitle {
margin-left: 40rpx;
margin-top: 60rpx;
}
.pro-selecttitle text {
font-size: 30rpx;
color: #292929;
}
.pro-productlists {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
margin-top: 10rpx;
}
.pro-productitem {
width: 90%;
height: 164rpx;
margin: auto;
border-bottom: 3rpx solid #dddddd;
}
.pro-productpic {
float: left;
width: 130rpx;
margin-top: 17rpx;
height: 130rpx;
}
.pro-productname {
position: absolute;
font-size: 32rpx;
color: #252525;
margin-top: 36rpx;
left: 180rpx;
}
.pro-productprice {
position: absolute;
font-size: 32rpx;
color: #252525;
left: 180rpx;
margin-top: 92rpx;
}
.pro-productadd {
float: right;
width: 60rpx;
height: 60rpx;
margin-top: 54rpx;
margin-right: 15rpx;
}
.pro-copyright {
width: 100%;
margin: 0;
padding: 0;
text-align: center;
}
.pro-copyrightitem {
margin: auto;
padding: 0;
margin-top: 50rpx;
margin-bottom: 190rpx;
}
.pro-copyrightmsg {
font-size: 26rpx;
color: #03a964;
margin-right: 40rpx;
text-decoration: underline;
}
.pro-copyrightprivate {
font-size: 26rpx;
color: #03a964;
text-decoration: underline;
}
.pro-bottominfo {
position: fixed;
bottom: 0;
width: 100%;
height: 130rpx;
background: white;
border-top: 3rpx solid #dddddd;
}
.pro-bottomprize {
position: absolute;
font-size: 24rpx;
color: #b3b3b3;
left: 40rpx;
top: 30rpx;
}
.pro-bottompriceinfo {
position: absolute;
left: 40rpx;
top: 60rpx;
text-align: left;
}
.pro-bottomprice {
font-size: 24rpx;
color: #252525;
font-weight: bold;
}
.pro-bottomprice2 {
font-size: 30rpx;
color: #252525;
font-weight: bold;
}
.pro-bottompay {
float: right;
width: 216rpx;
height: 74rpx;
background: #f7f7f7;
margin-top: 30rpx;
margin-right: 40rpx;
border-radius: 30rpx;
text-align: center;
}
.pro-bottompay text {
height: 100%;
font-size: 35rpx;
color: #b3b3b3;
line-height: 74rpx;
overflow: hidden;
}
.isDialogShow {
display: block;
}
.isDialogHide {
display: none;
}
.pro-dialog {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: rgba(0, 0, 0, .5);
z-index: 2;
text-align: center;
}
.pro-dialogdiv {
position: absolute;
width: 100%;
height: 970rpx;
bottom: 0;
text-align: center;
overflow: hidden;
}
.pro-dialog-topdiv {
width: 280rpx;
height: 280rpx;
background: white;
margin: auto;
border-radius: 140rpx;
overflow: hidden;
}
.pro-dialog-botdiv {
position: relative;
width: 100%;
height: 100%;
top: -140rpx;
background: white;
overflow: hidden;
border-top-left-radius: 18rpx;
border-top-right-radius: 18rpx;
}
.pro-dialog-content {
position: absolute;
width: 90%;
height: 100%;
margin: auto;
padding: 0;
left: 5%;
top: 0;
}
.pro-dialog-pic {
width: 200rpx;
height: 200rpx;
margin: 0;
padding: 0;
margin-top: 48rpx;
}
.pro-dialog-close {
position: absolute;
width: 60rpx;
height: 60rpx;
left: -10rpx;
top: 170rpx;
}
.pro-dailog-name {
position: absolute;
font-size: 32rpx;
color: black;
left: 0;
top: 300rpx;
}
.pro-dailog-price {
position: absolute;
font-size: 32rpx;
color: black;
left: 0;
top: 360rpx;
}
.pro-dialog-line {
width: 100%;
height: 3rpx;
margin-top: 190rpx;
background: #b3b3b3;
}
.pro-dialog-scroll {
width: 100%;
height: 100%;
margin-top: 10rpx;
overflow: hidden;
}
编辑gridinfo.js文件用于设置相关控件的数据信息。
// pages/gridinfo/gridinfo.js
Page({
/**
* 页面的初始数据
*/
data: {
barTitle:null,
toppic:null,
proList:[
{
"pic": "/images/img_bann1.jpg",
"name": "玩出我的夏天"
}, {
"pic": "/images/img_bann2.jpg",
"name": "你真棒"
}, {
"pic": "/images/img_bann3.jpg",
"name": "毕业季"
}, {
"pic": "/images/img_bann4.jpg",
"name": "干杯"
}, {
"pic": "/images/img_bann5.jpg",
"name": "求抱抱"
}, {
"pic": "/images/img_bann6.jpg",
"name": "宝贝谢谢你"
}
],
productList:[
{
"pic":"/images/img_product1.jpg",
"name":"当季特饮",
"price":40
}, {
"pic": "/images/img_product2.jpg",
"name": "馥芮白",
"price": 36
}, {
"pic": "/images/img_product3.jpg",
"name": "焦糖玛奇朵",
"price": 35
}, {
"pic": "/images/img_product4.jpg",
"name": "拿铁",
"price": 31
}, {
"pic": "/images/img_product5.jpg",
"name": "冷萃冰咖啡",
"price": 36
}, {
"pic": "/images/img_product6.jpg",
"name": "锦云冷萃",
"price": 42
}, {
"pic": "/images/img_product7.jpg",
"name": "星礼卡",
"price": 50
}, {
"pic": "/images/img_product7.jpg",
"name": "星礼卡",
"price": 100
}, {
"pic": "/images/img_product7.jpg",
"name": "星礼卡",
"price": 200
}, {
"pic": "/images/img_product7.jpg",
"name": "星礼卡",
"price": 288
}, {
"pic": "/images/img_product7.jpg",
"name": "星礼卡",
"price": 520
}
],
isShowDialog:false,
dialogPic:"",
dialogName:"",
dialogPrice:""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var self = this;
var proList = this.data.proList;
for (var i = 0; i < proList.length; i++) {
proList[i].showView = false;
}
proList[0].showView = true;
self.setData({
barTitle:options.name,
toppic:options.toppic,
proList:proList
})
},
toProListInfo: function (e) {
var index = e.currentTarget.dataset.index;
var proList = this.data.proList;
var name = proList[index].name;
var pic = proList[index].pic;
var self = this;
for (var i = 0; i < proList.length; i++) {
proList[i].showView = false;
}
proList[index].showView = true;
self.setData({
toppic: pic,
proList:proList
});
},
toProductAdd:function (e) {
var index = e.currentTarget.dataset.index;
var productList = this.data.productList;
var name = productList[index].name;
var price = productList[index].price;
wx.showToast({
title: name + ' ¥' + price,
})
},
toCopyrightMsg:function (e) {
wx.showToast({
title: '使用须知',
})
},
toCoprightPrivate:function (e) {
wx.showToast({
title: '隐私政策',
})
},
toPayInfo:function (e) {
wx.showToast({
title: '购买',
})
},
toProductInfo:function (e) {
var index = e.currentTarget.dataset.index;
var productList = this.data.productList;
var name = productList[index].name;
var price = productList[index].price;
var pic = productList[index].pic;
var self = this;
self.setData({
isShowDialog:true,
dialogPic:pic,
dialogName:name,
dialogPrice:price
})
},
toDialogClose: function (e) {
var self = this;
self.setData({
isShowDialog:false
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
var barTitle = this.data.barTitle;
wx.setNavigationBarTitle({
title:barTitle
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
(1)获取信息,设置标题
首先我们在也没加载时,通过生命周期函数onLoad,获取上个界面传递的信息,同时设置横向列表选中状态(默认选中第一个),并将获取到的数据保存到data。
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var self = this;
var proList = this.data.proList;
for (var i = 0; i < proList.length; i++) {
proList[i].showView = false;
}
proList[0].showView = true;
self.setData({
barTitle:options.name,
toppic:options.toppic,
proList:proList
})
}
然后,在onReady方法中调用wx.setNavigationBarTitle()方法,设置当前界面标题信息
onReady: function () {
var barTitle = this.data.barTitle;
wx.setNavigationBarTitle({
title:barTitle
})
}
(2)横向列表点击事件处理
横向列表的点击事件,主要处理两个问题,大图的切换和选中状态的处理。
toProListInfo: function (e) {
var index = e.currentTarget.dataset.index;
var proList = this.data.proList;
var name = proList[index].name;
var pic = proList[index].pic;
var self = this;
for (var i = 0; i < proList.length; i++) {
proList[i].showView = false;
}
proList[index].showView = true;
self.setData({
toppic: pic,
proList:proList
});
}
(3)商品弹窗的处理
通过isShowDialog设置弹窗的显示隐藏,同时根据弹窗index,设置弹窗内布局信息
toProductInfo:function (e) {
var index = e.currentTarget.dataset.index;
var productList = this.data.productList;
var name = productList[index].name;
var price = productList[index].price;
var pic = productList[index].pic;
var self = this;
self.setData({
isShowDialog:true,
dialogPic:pic,
dialogName:name,
dialogPrice:price
})
}
至此,列表界面和详情界面的效果基本实现,如有问题,欢迎留言