这几天浏览了很多小程序,感觉星巴克的小程序布局既简单又大方,结合之前所学的小程序知识来对其进行简单的模拟;
(注:仅仅限于学习,并不进行商业用途,哈哈^_^ 望周知!!!)
知识储备:
1)微信小程序组件【在这里主要使用了view / swiper / scroll-view / button / radio-group / image等组件】
2)微信小程序的页面渲染方式【使用this.setData({})以及{{}}的方式对数据进行渲染】(尽量少的使用this.setData)
3)小程序的页面样式【css的点单使用,主要有字体样式、轮廓样式、布局方式等】
在这里采取的布局样式主要为列表式(流式)、宫格式(flex)以及滚动式(swiper & scroll-view)
4)小程序api的简单使用【动画api / 登录api / 支付api / 获取系统数据api 等】
5)JavaScript基础【了解json数据的相关操作、数据类型、函数定义与使用、表达式与运算符等】
6)其他【涉及到日期数据的计算,通过new Date()和时间戳来计算日期】
一、主页信息: (使用微信小程序滚动式布局、流式布局以及简单的页面响应)
主页信息显示页面:(仅仅把数据接口给出,剩下的就是后台操作(后期补上 哈哈))
<!--pages/XBKindex/XBKindex.wxml-->
<swiper autoplay="true" indicator-dots="true" circular="true" indicator-color="#fff">
<block wx:for="{{swiperdata}}" wx:key="index">
<swiper-item>
<view class="box">
<image src="{{item.src}}" style="width:100%; height:100%;"></image>
</view>
</swiper-item>
</block>
</swiper>
<view class="mainbody">
<view class="title">咖啡+祝福,即刻表达心意</view>
<block wx:for="{{mainbodydata}}" wx:key="index">
<view class="subbox" >
<view class="item" bindtap="click" data-id="{{index}}">
<image src="{{item.src}}" style="width:100%;height:180rpx;"></image>
<view>{{item.name}}</view>
</view>
</view>
</block>
</view>
<view style="width:100%; text-align:center;">
<icon type="info" style="margin:auto;" size="36px" color="grey"></icon>
<navigator url="../XBKhistory/XBKhistory">购买历史</navigator>
</view>
二、商品项目信息:(使用微信小程序滚动式布局、流式布局以及简单的页面响应)
三、遮罩层+显示商品的详细信息(微信动画api、css以及日期计算(时间戳)的综合应用)
商品数据显示页面:(仅仅把数据接口给出,剩下的就是后台操作(后期补上 哈哈))
<!--pages/XBKitem/XBKitem.wxml-->
<scroll-view class="boxup" scroll-y="true" style="height:{{systemheight-25}}px;">
<view class="header">
<view class="box">
<image src="{{itemsrc}}" style="width:100%; height:100%;"></image>
</view>
</view>
<scroll-view class="Vscroll" scroll-x="true" enable-flex="true">
<radio-group style="height:134rpx; width:23%; margin-left:15rpx;" bindchange="changeCard">
<block wx:for="{{subcard}}" wx:key="index">
<image src="{{item.src}}" style=" width:100%; height:100%;"></image>
<radio value="{{index}}" checked="{{item.checked}}" class="radiostyle" />
</block>
</radio-group>
</scroll-view>
<view style="width:90%; margin:auto;">
<block wx:for="{{itemdata}}" wx:key="index">
<view class="iteminfo" bindtap="run" data-id="{{index}}">
<view class="cell1">
<image src="{{item.src}}" style="height:100%; width:100%;"></image>
</view>
<view class="cell2">
<view class="showitem">{{item.name}} </view>
<view class="showitem">¥{{item.value}} </view>
</view>
<view class="cell3">
<view wx:if="{{item.thisnum!=0?true:false}}" class="subleft">
<icon type="info" class="rotate180" color="gray" size="30px" catchtap="delayThing" data-id="{{index}}"></icon>
<view style="position: absolute; left:105%; top:8%;width:50rpx; text-align:center;">{{item.thisnum}}</view>
</view>
<view wx:else style="width:60%;"></view>
<view class="subright">
<icon type="cancel" class="rotate" color="gray" size="30px" catchtap="addThing" data-id="{{index}}"></icon>
</view>
</view>
</view>
</block>
<view class="otherInfo">
<view class="right F">使用须知</view>
<view class="right F">隐私权条款</view>
</view>
</view>
</scroll-view>
<view class="boxbottom">
<view class="left">
<view class="textup">{{giftnum}}份礼品</view>
<view class="textdown">¥{{giftvalue}}</view>
</view>
<view class="right">
<button bindtap="PayFor" disabled="{{!giftnum}}">购买</button>
</view>
</view>
<view style="position: absolute; top:0rpx;">
<view class='maskLayer' wx:if="{{flag}}" bindtap='cancellevel' style="height:{{systemheight+20}}px;"></view>
<view class="hideLevel" style="top:{{systemheight-240}}px" wx:if="{{flag}}" animation="{{animation1}}">
<view style="height:600rpx;">
<view class="hideMode">
<icon type="cancel" size="32px" color="grey" style="position: absolute; left:6rpx;" bindtap="cancellevel"></icon>
<image src="{{cardsrc}}" style="width:300rpx;height:300rpx; margin:auto;" id="Img"></image>
</view>
<scroll-view scroll-y="true" style="height:200rpx; width:95%; margin:auto;">
<view class="subtitle">
<view>{{cardname}}</view>
<view>¥ {{cardvalue}}</view>
</view>
<view class="subcontext">
<view>使用门店:全部门店均可使用</view>
<view>有效时段:{{nowtime}}-{{deadtime}}</view>
<view>使用须知:仅限本人使用,本套餐有效期限为成功购买之日算起至{{deadtime}}。本套餐为一次性使用产品,一旦使用即刻失效!</view>
</view>
</scroll-view>
</view>
</view>
</view>
小程序主页信息的wxss样式文件
/* pages/XBKindex/XBKindex.wxss */
.box {
height: 500rpx;
}
swiper {
margin-bottom: 20rpx;
}
.mainbody {
width: 95%;
margin: auto;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.title {
font-size: 30rpx;
color: gray;
letter-spacing: 1pt;
width: 100%;
margin-bottom: 15rpx;
}
.subbox {
width: 50%;
text-align: center;
margin: auto;
height: 255rpx;
margin-bottom: 10rpx;
}
.item {
width: 90%;
text-align: center;
height: 230rpx;
margin: auto;
box-shadow: 0 0 16rpx gainsboro;
font-size:28rpx;
letter-spacing: 1pt;
border-radius:10rpx;
}
image{
border-radius: 15rpx;
}
navigator{
color: green;
text-underline-position: below;
letter-spacing: 1pt;
font-size: 30rpx;
}
商品项目的wxss样式文件 (写的有点繁杂其实可以把相同的部分抽取出来写在app.wxss中,这里就不在改了)
/* pages/XBKitem/XBKitem.wxss */
page{
z-index:0;
}
.header {
width: 100%;
height: 300rpx;
margin-bottom: 15rpx;
padding-top: 20rpx;
}
.box {
margin: auto;
width: 80%;
height: 270rpx;
border-radius: 12rpx;
box-shadow: 0 0 12rpx grey;
}
.Vscroll {
white-space: nowrap;
display: flex;
margin-bottom: 6rpx;
height: 150rpx;
}
.item {
width: 25%;
height: 135rpx;
display: inline-block;
border: 1rpx solid black;
border-radius: 15rpx;
margin: 0 16rpx;
}
.iteminfo {
display: flex;
flex-direction: row;
height: 200rpx;
margin-top: 5rpx;
padding-top: 10rpx;
border-bottom: 1rpx solid gainsboro;
}
.cell1 {
flex: 0.8;
margin: 20rpx 5rpx;
text-align: left;
box-shadow: 0 0 3rpx dimgray;
}
.cell2 {
flex: 1;
margin: 20rpx 5rpx;
}
.cell3 {
flex: 2;
text-align: right;
margin: 20rpx 5rpx;
display: flex;
flex-direction: row;
}
.rotate {
transform: rotate(45deg);
}
.showitem {
margin-left: 16rpx;
margin-top: 12rpx;
}
.boxup {
width: 100%;
height: 100%;
}
.boxbottom {
margin-top: 10rpx;
display: flex;
width: 100%;
flex-direction: row;
}
.left {
flex: 2;
display: flex;
flex-direction: column;
}
.right {
flex: 1;
}
button {
width: 50%;
background-color: green;
color: #fff;
margin: auto;
}
.textup {
font-size: 30rpx;
letter-spacing: 1pt;
color: gray;
margin-left: 16rpx;
}
.textdown {
font-weight: 600;
margin-left: 16rpx;
}
.rotate180 {
transform: rotate(90deg);
margin-top: 0rpx;
}
.subleft {
width: 60%;
position: relative;
margin-top: 38rpx;
}
.subright {
width: 40%;
margin-top: 38rpx;
height: 25px;
}
.radiostyle {
position: relative;
left: -25rpx;
top: -5rpx;
}
.hideMode{
width: 95%;
margin: auto;
position: relative;
text-align: center;
padding-bottom: 20rpx;
}
#Img{
position: relative;
top:-66rpx;
border-radius: 16rpx;
box-shadow: 0 0 15rpx grey;
}
.subtitle{
border-bottom: 1rpx solid gray;
padding-bottom: 58rpx;
line-height: 1.8;
letter-spacing: 1pt;
}
.subcontext{
font-size: 32rpx;
line-height: 1.6;
height:225rpx;
}
.hideLevel{
position: relative;
background: #fff;
}
.maskLayer{
position: absolute;
background-color:gainsboro;
opacity: 0.8;
width: 100%;
}
.otherInfo{
display: flex;
flex-direction: row;
width: 66%;
margin: 36rpx auto;
text-align: center;
}
.F{
font-size: 32rpx;
color: green;
}
(注:在小程序中要尽量避免将样式信息直接写在wxml中,会降低页面的渲染速度,出现在wxml中的组件style要尽可能
的少,后期做后台的时候我会尽量将上述问题进行更正 ! ^_^ !)
小程序主页的js文件(这里采用的数据信息均为静态数据,后期可以按照此种数据定义格式接收后台传递过来的数据)
// pages/XBKindex/XBKindex.js
Page({
/**
* 页面的初始数据
*/
data: {
swiperdata: [{ src: "../image/ad1.jpg" }, { src: "../image/ad2.jpg" }, { src: "../image/ad3.jpg" }, { src: "../image/ad4.jpg" }, { src: "../image/ad5.jpg" }],
mainbodydata: [{ src: "../image/XBK1.jpg", name: "心悦传情" }, { src: "../image/XBK2.jpg", name: "给力伙伴" }, { src: "../image/XBK3.jpg", name: "感恩有你" }, { src: "../image/XBK4.jpg", name: "有你真好" }, { src: "../image/XBK5.jpg", name: "咖啡有你" }, { src: "../image/XBK6.jpg", name: "生日快乐" }, { src: "../image/XBK7.jpg", name: "DIY以表心意" }, { src: "../image/XBK8.jpg", name: "其妙时刻" }]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
click:function(e){
var index = e.currentTarget.dataset.id
var sendsrc = this.data.mainbodydata[index].src
wx.navigateTo({
url: '../XBKitem/XBKitem?itemsrc=' + sendsrc,//后期加传递的参数
})
}
})
商品项目的js文件信息:(这里采用的数据信息均为静态数据,后期可以按照此种数据定义格式接收后台传递过来的数据)
// pages/XBKitem/XBKitem.js
Page({
/**
* 页面的初始数据
*/
data: {
itemdata: [{
src: "../image/item1.jpg",
name: "果味拿铁",
value: 100,
thisnum: 0
}, {
src: "../image/item2.jpg",
name: "森林摩卡",
value: 150,
thisnum: 0
}, {
src: "../image/item3.jpg",
name: "拿铁",
value: 80,
thisnum: 0
},
{
src: "../image/item4.jpg",
name: "咖啡",
value: 50,
thisnum: 0
},
{
src: "../image/item5.jpg",
name: "果味探戈",
value: 100,
thisnum: 0
}, {
src: "../image/item6.jpg",
name: "果味牛奶",
value: 100,
thisnum: 0
}, {
src: "../image/item7.jpg",
name: "醋意涛涛",
value: 100,
thisnum: 0
}
], //主体部分的数据信息
subcard: [{
src: "../image/ad1.jpg",
checked: true
}, {
src: "../image/ad2.jpg",
checked: false
}, {
src: "../image/ad3.jpg",
checked: false
}, {
src: "../image/ad4.jpg",
checked: false
}, {
src: "../image/ad5.jpg",
checked: false
}], //横向滚动部分图片
giftnum: 0, //购物总数量
giftvalue: 0, //购物总价格
systemheight: 0, //机型的屏幕高度
itemsrc: "../image/XBK2.jpg", //head的图片
animation1: null,
flag: false,
cardname: "",
cardvalue: "",
cardsrc: "",
deadtime: "",
nowtime: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
var height = wx.getSystemInfoSync().windowHeight
this.setData({
systemheight: height,
itemsrc: options.itemsrc
})
//页面加载获取初始信息height和背景图片
var timestamp = Date.parse(new Date()) //获取当前时间戳
timestamp = timestamp / 1000 + 24 * 60 * 60 * 60;
var dtime = new Date(timestamp * 1000)
this.setData({
nowtime: new Date().getFullYear() + "." + (new Date().getMonth() + 1) + "." + new Date().getDate(),
deadtime: dtime.getFullYear() + "." + (dtime.getMonth() + 1) + "." + dtime.getDate()
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function() {
},
addThing: function(e) {
var thisthing = this.data.itemdata
var index = e.currentTarget.dataset.id
var nownum = this.data.giftnum + 1
var nowvalue = this.data.giftvalue
thisthing[index].thisnum = thisthing[index].thisnum + 1
nowvalue = nowvalue + thisthing[index].value
this.setData({
giftnum: nownum,
giftvalue: nowvalue,
itemdata: thisthing
})
//添加购买商品
},
delayThing: function(e) {
var thisthing = this.data.itemdata
var index = e.currentTarget.dataset.id
var nownum = this.data.giftnum - 1
var nowvalue = this.data.giftvalue
thisthing[index].thisnum = thisthing[index].thisnum - 1
nowvalue = nowvalue - thisthing[index].value
this.setData({
giftnum: nownum,
giftvalue: nowvalue,
itemdata: thisthing
})
//删除已购商品
},
changeCard: function(e) {
var list = this.data.subcard
var changesrc = this.data.subcard[e.detail.value].src
this.setData({
itemsrc: changesrc //点击单选按钮改变图片
})
//改变背景图片
},
run: function(e) {
var index = e.currentTarget.dataset.id
var list = this.data.itemdata
var showname = list[index].name;
var showvalue = list[index].value;
var showimgsrc = list[index].src;
this.setData({
cardname: showname,
cardvalue: showvalue,
cardsrc: showimgsrc,
})
var animation = wx.createAnimation({
duration: 1500,
delay: 0
})
this.animation = animation
animation.opacity(0).translateY(400).opacity(1).step()
this.setData({
animation1: animation.export(),
flag: true
})
var that = this
setTimeout(function() {
animation.translateY(0).step()
that.setData({
animation1: animation.export()
})
}, 150)
},
cancellevel: function() {
var animation = wx.createAnimation({
duration: 1000,
timingFunction: "ease",
delay: 0
})
this.animation = animation
animation.translateY(400).opacity(0).step()
this.setData({
animation1: animation.export(),
})
var that = this
setTimeout(function() {
animation.translateY(0).step()
that.setData({
animation1: animation.export(),
flag: false
})
}, 400)
},
PayFor:function(){
//后台处理操作,需要申请微信证书
wx.login({
success:function(res){
console.log('登录成功')
wx.requestPayment({
timeStamp: '',
nonceStr: '',
package: '',
signType: 'MD5',
paySign: '',
'success': function (res) {
console.log('支付成功')
},
fail: function (res) {
console.log('支付失败')
}
})
}
})
}
})
图片的url,我这里是放在image文件夹下的。但在实际的具体小程序中这样做是不被允许的仅仅限于在本机进行调试,在
上传小程序时会有大小限制(2M)。这些图片数据,可以保存在小程序的云端,根据需要进行调用;对于要绑定的数据
信息可以通过java / .Net c# / PHP对后台进行操作返回 json 数据,小程序通过require来引入外部数据。
感受:经过这几周对微信小程序的学习,自我感觉已经初步了解了整个微信小程序的开发流程,不得不说小程序的开发
速度就是快(相比与传统pc页面的制作)。在接下来的时间内要继续学习小程序的常用api(如:支付api、定位api等)
并加强自己对于后台相关知识的学习。同时,为了更好的实现界面效果要进一步学习JavaScript高级内容。
目标:在2-3个月内做一个完整的微信小程序,为自己以后的项目实践积累经验。(转战小程序云开发,Fighting!)
(大家喜欢的话,给个支持呗。哈哈)
在最美的年纪,别辜负最好的自己!把每一句“我不会”都改为“我可以学”,你就进步了!尝试总比永远不敢开始要强!