博客班级 | https://edu.cnblogs.com/campus/zjcsxy/SE2020 |
作业要求 | https://edu.cnblogs.com/campus/zjcsxy/SE2020/homework/11334 |
作业目标 |
|
作业源代码 | https://github.com/aiai0603/software-engineering-demo-1.git |
学号/姓名 | 31801150/张帅 |
院系 | 浙大城市学院计算机系 |
前言:软件工程课程的第一次作业,单独完成一个简单的微信小程序(不含后台),本文主要讲解如何从0基础入门来编写,含源代码和注解。本人纯小白,大佬勿喷,有错误请批评指正。
最终作品地址:https://github.com/aiai0603/software-engineering-demo-1.git(仅供参考)
开发工具:微信开发者工具
效果演示
(预览版)
全局配置
app.json:
pages:配置微信的小程序的所有页面。第一项"pages/index/index"为默认显示的界面,本程序包含9个界面。
1 "pages/index/index", //个人信息首页 2 "pages/logs/logs", //奖券列表展示页 3 "pages/main/main", //主页 4 "pages/rule/rule", //积分规则 5 "pages/policy/policy", //隐私政策 6 "pages/score/score", //积分页面 7 "pages/set/set", //个人设置 8 "pages/show/show", //领券页面 9 "pages/shop/shop" //积分商店
windows:全局配置页面效果,具体请参看官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/config.html
1 "window":{ 2 "backgroundTextStyle":"dark", 3 "navigationBarBackgroundColor": "#f21515", 4 "navigationBarTitleText": "Happy everyday", 5 "navigationBarTextStyle":"black", 6 "enablePullDownRefresh": true 7 },
tabbar:下方导航条配置,设置导航条的文字和图标
1 "tabBar": { 2 "selectedColor": "#f21515", //选中时文字颜色 3 "list": [{ 4 "pagePath": "pages/main/main", //跳转的页面 5 "text": "首页", //文字 6 "iconPath":"pages/1.jpg" , //未选中时显示的图表 7 "selectedIconPath": "pages/1-1.jpg" //选中时的图标 8 },{ 9 "pagePath": "pages/logs/logs", 10 "text": "优惠券", 11 "iconPath":"pages/3.jpg" , 12 "selectedIconPath": "pages/3-3.jpg" 13 },{ 14 "pagePath": "pages/index/index", 15 "text": "我的", 16 "iconPath":"pages/2.jpg" , 17 "selectedIconPath": "pages/2-2.jpg" 18 }] 19 }
app.js:
globalData:全局变量,用于存储数据,模拟变化。
1 globalData: { 2 userInfo: null, //个人信息 3 disabled:false, //控制按钮是否可用 4 color:"red", //控制按钮颜色 5 pricenum:3, //控制持有券数 6 price:[ //持有券的列表 7 { 8 available:0, //是否可用 9 count:2, //折扣 10 money:3, //满多少可用 11 name:"雪碧满3减2券", //券名 12 day:"2020.1.1-2021.1.1可用" //说明 13 }........(此处省略) 14 ], 15 score:[{ //积分信息 16 day:"2020/10/11 12:00:31", //时间 17 title:"签到奖励", //说明 18 point:2 //获得积分数 19 }........(此处省略)], 20 scorenum:506, //积分总数 21 sign:"签到", //签到按钮文字 22 style:"qd" //签到按钮样式名 23 }, 24
分页代码
在每一页的json文件中,设置好每一页的标题文字和颜色
1 { 2 "usingComponents": {}, //使用组建(本dome未使用) 3 "navigationBarTitleText": "我的", //标题文字 4 "navigationBarTextStyle":"white", //标题颜色 5 }


1 <view class="container"> 2 <view class="userinfo"> 3 <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo">授权登录 </button> 4 <block wx:else> 5 <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image> 6 <text class="userinfo-nickname">{{userInfo.nickName}}</text> 7 </block> 8 </view>
index.js
1 onLoad: function () { 2 if (app.globalData.userInfo) { //如果全局变量中已经存在授权信息则赋值给当前页面的变量 3 this.setData({ 4 userInfo: app.globalData.userInfo, 5 hasUserInfo: true 6 }) 7 } else if (this.data.canIUse){ 8 // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 9 // 所以此处加入 callback 以防止这种情况 10 app.userInfoReadyCallback = res => { 11 this.setData({ 12 userInfo: res.userInfo, 13 hasUserInfo: true 14 }) 15 } 16 } else { 17 // 在没有 open-type=getUserInfo 版本的兼容处理 18 wx.getUserInfo({ 19 success: res => { 20 app.globalData.userInfo = res.userInfo 21 this.setData({ 22 userInfo: res.userInfo, 23 hasUserInfo: true 24 }) 25 } 26 }) 27 } 28 }, 29 30 getUserInfo: function(e) { //获得授权的者的微信名 31 console.log(e) 32 app.globalData.userInfo = e.detail.userInfo 33 this.setData({ 34 userInfo: e.detail.userInfo, 35 hasUserInfo: true 36 }) 37 }
下方为view标签编写的功能栏,使用navigator标签实现跳转到指定的页面
PS:navigator标签只能跳转到非tabbar的页面,跳转到tabbar界面需要使用函数:
1 wx.switchTab({ //跳转至tabbar页面 2 url: '../logs/logs' 3 }) 4 5 <navigator url="../score/score"> //跳转到非tabbar界面
pages/logs/logs(优惠券的展示页面):
要调用全局变量,需要在js文件开头写上调用语句
1 var app=getApp();
将全局变量的值赋值给当前页面的变量,即可在当前页面使用
1 onShow: function () { 2 this.setData({ 3 price:app.globalData.price 4 })
头部使用选项卡检索“未使用”和“历史记录”的信息,绑定事件点击切换
logs.wxml
1 <view id='tabs'> 2 <view class='tabs-box'> 3 <block wx:for="{{['未使用','历史记录']}}" wx:key="index"> 4 <view class="tabs-item {{currentTabIndex == index ? 'selected' : '' }}" bindtap='onTabsItemTap' data-index='{{index}}'> 5 {{item}} 6 </view> 7 </block> 8 </view> 9 <view class='ordert-detail'> 10 <view hidden='{{currentTabIndex != 0}}'>(省略) 11 </view> 12 <view hidden='{{currentTabIndex != 1}}'>(省略)
13 </view> 14 </view>
logs.js
1 onTabsItemTap:function(event){ 2 let index=event.currentTarget.dataset.index; 3 this.setData({ 4 currentTabIndex:index, 5 }) 6 }
使用wx:for将数据渲染到页面中,使用availabel判断为哪种优惠券,从而渲染到不同的选项下,并绑定不同的样式
1 <view class="card" wx:for="{{price}}" wx:if="{{item.available!=0}}"> 2 <view class="left-2"> 3 <view class="left-title">¥{{item.count}}</view> 4 <view class="left-under">满{{item.money}}元可用</view> 5 </view> 6 <view class="word"> 7 <view class="title"> 8 {{item.name}} 9 </view> 10 <view class="under"> 11 12 {{item.day}} 13 </view> 14 </view> 15 </view>
pages/policy/policy、pages/rule/rule、pages/set/set :(三张简单的内容页面,不过多赘述)
pages/main/main(主页):
上方为与个人信息页相同的授权判定,授权则显示用户信息,未授权则显示登录按钮。签到按钮通过全局变量中的sign判断是否曾签到过,并在签到后改变样式
main.wxml
1 <view class="{{style}}" bindtap="sign" >{{sign}}</view>
main.js
1 var util = require('../../utils/util.js'); //导入官方自带的js文件,内含时间处理函数 2 sign:function(){ 3 if( app.globalData.sign=="签到") //判断是否曾签到 4 { 5 console.log("ok") 6 app.globalData.sign="已签" 7 app.globalData.style="qd-1" //改变样式 8 app.globalData.scorenum=app.globalData.scorenum+2 //改变总积分 9 var newpoint={ 10 day: util.formatTime(new Date()), 11 title:"签到奖励", 12 point:2 13 } 14 app.globalData.score.unshift(newpoint); //在积分信息数组中加入新的数据 15 this.setData({ //修改当前界面的数据,及时刷新 16 style:"qd-1", 17 sign:"已签", 18 score:app.globalData.scorenum 19 }) 20 }else{ 21 } 22 },
下方使用swiper组件实现轮播
pages/show/show(领券页面):
领券按钮主要通过全局变量disabled判断是否已经领过券,第一次领取则领取成功并弹窗
show.wxml
1 <button disabled="{{disabled}}" bindtap="get" style="width:200rpx;color:white;background-color:{{color}}" >领取</button>
show.js
get(){ wx.showToast({ //弹窗 title: '领取成功!', // 标题 icon: 'success', // 图标类型,默认success duration: 1500 // 提示窗停留时间,默认1500ms }), app.globalData.color="grey", app.globalData.disabled=true, app.globalData.pricenum+=1, //修改了全局变量 console.log(app.globalData.disabled) this.setData({ color:"grey", disabled:true //在当前界面更新 }) var newprice={ available:0, count:2, money:4, name:"雪碧满4减2券", day:"2020.1.1-2021.1.1可用" } app.globalData.price.push(newprice) //将新的优惠券信息插入全局数组中 },
pages/score/score(积分界面):
积分信息的渲染同优惠券界面,筛选功能通过picker组件控制,选择后重置当前界面的数组,使得当前界面的信息发生改变
score.wxml
1 <picker mode="selector" bindchange="bindPickerChange" value="{{index}}" range="{{array}}"> 2 <view class="button" >筛选</view> 3 </picker>
score.js
1 data: { 2 array: ['全部', '增加', '减少'], //绑定在选择器的数据 3 objectArray: [ 4 { 5 id: 0, 6 name: '全部' 7 }, 8 { 9 id: 1, 10 name: '增加' 11 }, 12 { 13 id: 2, 14 name: '减少' 15 } 16 ], 17 index: 0 //当前所选的条目的下标 18 },
1 bindPickerChange: function (e) { 2 console.log('picker发送选择改变,携带值为', e.detail.value) 3 this.setData({ 4 index: e.detail.value //绑定选择的下标 5 }) 6 if(e.detail.value==0) //下标为0则全选,将完整的数组赋值给当前 7 { 8 this.setData({ 9 score:app.globalData.score 10 }) 11 }else if(e.detail.value==1){ //下标为1,选择增加积分的页面 12 var i; 13 var temp=[]; 14 for(i=0;i<app.globalData.score.length;i++) //遍历数组,找出增值为正的值存入中间tmp数组 15 { 16 if(app.globalData.score[i].point>0){ 17 temp.push(app.globalData.score[i]); 18 } 19 } 20 this.setData({ 21 score:temp //修改为处理后的数组 22 }) 23 }else{ //检索减少的值为同理 24 var i; 25 var temp=[]; 26 for(i=0;i<app.globalData.score.length;i++) 27 { 28 if(app.globalData.score[i].point<0){ 29 temp.push(app.globalData.score[i]); 30 } 31 } 32 this.setData({ 33 score:temp 34 }) 35 } 36 }
pages/shop/shop(积分商城):
通过wx:for将商品信息绑定至界面。点击时将点击的商品卡片对应的信息传入函数,函数比较当前积分和商品所需积分,满足需求弹出确认窗口,积分不足则弹出提示框
shop.wxml
1 <view class="card-group" > 2 <view class="card" wx:for="{{shop}}" wx:key="{{item.index}}" bindtap="buy" data-item="{{item}}"> 3 <image class="img" src="{{item.src}}"> 4 </image> 5 <view class="title"> 6 {{item.title}} 7 </view > 8 <view class="score"> 9 {{item.point}}积分 10 </view> 11 </view>
shop.js
1 buy(e){ 2 var good = e.currentTarget.dataset.item; //获得当前商品信息 3 if(good.point>=app.globalData.scorenum) //比较积分是否满足 4 { 5 wx.showToast({ //积分不足,弹出纯文字信息 6 title: '积分不足', 7 icon: 'none', //如果要纯文本,不要icon,将值设为'none' 8 duration: 2000 9 }) 10 }else{ 11 let that = this; //保存当前page信息,在后续回调函数中this将无法调用 12 wx.showModal({ //确认框 13 title:"确认", 14 content:"将扣除500积分,您确定吗?", 15 success:function(res){ //确认兑换,扣除积分 16 if(res.confirm){ 17 app.globalData.scorenum-=good.point; 18 19 that.setData({ 20 score:that.data.score-good.point 21 }) 22 wx.showToast({ 23 title: '兑换成功', 24 icon: 'none', 25 duration: 1000 26 }) 27 28 var newprice={ 29 available:0, 30 count:1, 31 money:3, 32 name:"可乐满3减1券", 33 day:"2020.1.1-2021.1.1可用" 34 } 35 app.globalData.price.push(newprice); //把兑换的券加入券的数组 36 37 var newpoint={ 38 day: util.formatTime(new Date()), 39 title:"兑换商品", 40 point:-500 41 } 42 app.globalData.score.unshift(newpoint); //吧兑换的积分信息加入积分信息的数组 43 app.globalData.pricenum+=1; 44 } 45 else if(res.cancel){ 46 wx.showToast({ //取消兑换,弹出信息 47 title: '已经取消', 48 icon: 'none', //如果要纯文本,不要icon,将值设为'none' 49 duration: 1000 50 }) 51 }} 52 }) 53 } 54 },
收获总结
虽然是软件工程作业的第一份作业,也着实花了不少功夫,从0基础到完成一份较为完善的小demo,一步步查找文档和资料,将一个个功能完善。其中也经过了不少的弯路,犯了不少错误。希望在今后的编码中,可以吸取这次开发的经验,将这次写demo的经验用在之后的大作业和编码中。同时,可以继续保持认真学习,自主学习的态度,同时向周围优秀的同学学习,继续完善持续跟进软件工程的学习。