| 博客班級 | https://edu.cnblogs.com/campus/zjcsxy/SE2020 |
| 作業要求 | https://edu.cnblogs.com/campus/zjcsxy/SE2020/homework/11334 |
| 作業目標 | 完成一個小程序,上傳代碼,完成一篇博文 |
| 作業源代碼 | https://github.com/blank-hk1/WX-miniapps.git |
| 學號 | 31801149-何科 |
| 院系 | 浙大城院計算機系 |
項目描述: 本項目主要完成了一個類似於漂流瓶小程序的簡易搭建,采用了微信雲開發的數據庫后台,實現了扔撿的功能。該項目主要包括了首頁展示,漂流瓶扔,撿功能的簡易實現,以及個人信息的展示。
項目頁面展示







全局配置:
JSON文件(app.json):
{
"pages": [
"pages/index/index",//登錄界面
"pages/zy/zy",//首頁
"pages/write/write",//扔漂流瓶界面
"pages/mine/mine",//我的漂流瓶
"pages/get/get"//撿漂流瓶界面
],
"window": { //登錄界面樣式
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#26A5FF",
"navigationBarTitleText": "漂流瓶",
"navigationBarTextStyle": "black"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
JS文件(app.js) :
//app.js App({ onLaunch: function () { // 展示本地存儲能力 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) // 登錄 wx.login({ success: res => { // 發送 res.code 到后台換取 openId, sessionKey, unionId } }) // 獲取用戶信息 wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { // 已經授權,可以直接調用 getUserInfo 獲取頭像昵稱,不會彈框 wx.getUserInfo({ success: res => { // 可以將 res 發送給后台解碼出 unionId this.globalData.userInfo = res.userInfo // 由於 getUserInfo 是網絡請求,可能會在 Page.onLoad 之后才返回 // 所以此處加入 callback 以防止這種情況 if (this.userInfoReadyCallback) { this.userInfoReadyCallback(res) } } }) } } }) }, globalData: { //定義全局變量 userInfo: null, throw:0, get:0 } })
各頁面代碼:
首頁
wxml文件:
<!--pages/zy/zy.wxml-->
<view>
<!--輪播圖-->
<swiper class='lunbo' indicator-dots='true' autoplay='true' interval='4000'> //利用swiper組件實現輪播動畫
<swiper-item> <image src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1602684860769&di=39fce0bf578183478d1a389ab76cea9d&imgtype=0&src=http%3A%2F%2Fdpic.tiankong.com%2Fdn%2F0m%2FQJ8477065702.jpg'></image> </swiper-item>
<swiper-item> <image src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1602682402604&di=90242ef9939b6c7f72119f15485bd34c&imgtype=0&src=http%3A%2F%2Fimg1.juimg.com%2F160409%2F330800-16040911292961.jpg'></image></swiper-item>
<swiper-item> <image src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1602682432669&di=01182e87ae641423b81226a767b6f6b4&imgtype=0&src=http%3A%2F%2Ffile03.16sucai.com%2F2017%2F1100%2F16sucai_P59201F287.JPG'></image> </swiper-item>
</swiper>
</view>
<view class="sj">
<text>截止目前, \n</text>
<text> \n</text>
<text>您已經扔了</text>
<text>{{throwing}}</text>//全局變量,實時更改扔出數量
<text>個漂流瓶, \n</text>
<text> \n</text>
<text>您已經撿了{{geting}}個漂流瓶。 \n</text>//全局變量,實時更改撿到數量
</view> <view class="play-style"> <view class="leftstyle"> <image class="img" src="{{throwSrc}}" bindtap="throw"></image> <text>扔一個</text> </view> <view class="playstyle"> <image class="img" src="{{getSrc}}" bindtap="get"></image> <text>撿一個</text> </view> <view class="rightstyle"> <image class="img" src="{{mySrc}}" bindtap="mine"></image> <text>我的瓶子</text> </view> </view>
JS文件
// pages/zy/zy.js var app = getApp() Page({ data: { getSrc: "../../images/a.png",//撿一個 throwSrc: "../../images/b.png",//扔一個 mySrc: "../../images/c.png",//我的 throwing:0, geting:"" }, //撿一個 onShow:function(){ console.log(app.globalData.throw) this.setData({ throwing:app.globalData.throw, geting:app.globalData.get }) }, get: function () { console.log("撿一個") //隨機去后台拉取一個錄音 wx.navigateTo({ url: '../get/get', success: function (res) { // success }, fail: function () { // fail }, complete: function () { // complete } }) }, //扔一個 throw: function () { console.log("扔一個") wx.navigateTo({ url: '../write/write', success: function (res) { // success }, fail: function () { // fail }, complete: function () { // complete } }) }, //我的瓶子 mine: function () { console.log("我的瓶子") wx.navigateTo({ url: '../mine/mine', success: function (res) { // success }, fail: function () { // fail }, complete: function () { // complete } }) } })
在主頁的界面中通過全局變量throw和get來實時更新主頁的數據:
要調用全局變量,需要在js文件開頭寫上調用語句
var app=getApp();
之后再通過按鈕的點擊來改變全局變量的值,即可在主頁顯示
onShow:function(){ console.log(app.globalData.throw) this.setData({ throwing:app.globalData.throw, geting:app.globalData.get }) },
扔漂流瓶界面:

可以通過文字和語音輸入漂流瓶文本,如果沒有輸入內容會彈出相關提示。
wxml文件:
<!--write.wxml--> <view class="weui-cells weui-cells_after-title"> <view class="weui-cell"> <view class="weui-cell__bd"> <textarea wx:if="{{!isInput}}" class="weui-textarea" placeholder="請輸入文本" style="height: 16em;" bindblur="bindTextAreaBlur" /> </view> </view> </view> <view wx:if="{{isSpeaking}}" class="speak-style"> <image class="sound-style" src="../../images/voice_icon_speech_sound_1.png" ></image> <image wx:if="{{j==2}}" class="sound-style" src="../../images/voice_icon_speech_sound_2.png" ></image> <image wx:if="{{j==3}}" class="sound-style" src="../../images/voice_icon_speech_sound_3.png" ></image> <image wx:if="{{j==4}}" class="sound-style" src="../../images/voice_icon_speech_sound_4.png" ></image> <image wx:if="{{j==5}}"class="sound-style" src="../../images/voice_icon_speech_sound_5.png" ></image> </view> <image wx:if="{{bottle}}" class="bottle-style" animation="{{animationBottle}}" src="../../images/bottle.png" ></image> <view class="play-style"> <image style="margin:20rpx;height:80rpx;width:80rpx;" src="{{isInput?jp:ht}}" bindtap="inputSwitch"></image> <button class="btn-style" bindtouchstart="touchdown" bindtouchend="touchup" bindtap="throwBottle">{{isInput?"按住 說話":"扔出去"}}</button> </view>
JS文件:
//write.js //獲取應用實例 var app = getApp() const db = wx.cloud.database({}) const cont = db.collection('hkcloud') Page({ data: { jp: "../../images/jp.png", ht: "../../images/ht.png", isInput: true,//默認鍵盤輸入 j: 1,//幀動畫初始圖片 isSpeaking: false,//是否正在說話 animationBottle: {},//扔出漂流瓶動畫 bottle: false,//漂流瓶 contentInput: '',//內容 num:0 }, onLoad: function () { //在leancloud生成目錄 // 聲明類型 // var TodoFolder = AV.Object.extend('TodoFolder'); // 新建對象 // var todoFolder = new TodoFolder(); // 設置名稱 // todoFolder.set('name', "文本漂流瓶"); // 設置優先級 // todoFolder.set('priority', 1); // todoFolder.save().then(function (todo) { // console.log('objectId is ' + todo.id); // }, function (error) { // console.error(error); // }); }, onReady: function () { // 標題欄 wx.setNavigationBarTitle({ title: '扔一個' }) }, //切換話筒和鍵盤 inputSwitch: function () { this.setData({ isInput: !this.data.isInput }) }, //手指按下 touchdown: function () { var _this = this; //話筒的時候,點擊按鈕無效 if (!this.data.isInput) return this.data.contentInput console.log("new date : " + new Date) speaking.call(this); this.setData({ isSpeaking: true }) //開始錄音 wx.startRecord({ success: function (res) { //臨時路徑,下次進入小程序時無法正常使用 var tempFilePath = res.tempFilePath console.log("tempFilePath: " + tempFilePath) //錄音完成后直接上傳,不再持久保存本地 //持久保存 //wx.saveFile({ // tempFilePath: tempFilePath, // success: function (res) { //持久路徑 //本地文件存儲的大小限制為 100M //var savedFilePath = res.savedFilePath //console.log("savedFilePath: " + savedFilePath) // } // }) wx.showToast({ title: '恭喜!錄音成功', icon: 'success', duration: 1000 }) }, fail: function (res) { //錄音失敗 wx.showModal({ title: '提示', content: '錄音的姿勢不對!', showCancel: false, success: function (res) { if (res.confirm) { console.log('用戶點擊確定') return } } }) } }) }, //手指抬起 touchup: function () { //話筒的時候,點擊按鈕無效 if (!this.data.isInput) return console.log("手指抬起了...") clearInterval(this.timer) wx.stopRecord() //開發工具測試有效.真機不執行. throwBottleAnimation.call(this); this.setData({ isSpeaking: false, }) }, //扔出去 //獲取多行輸入框內容 bindTextAreaBlur: function (e) { //console.log(e.detail.value) this.setData({ contentInput: e.detail.value }); }, throwBottle: function () { let self = this; var _this = this; //鍵盤的時候,點擊按鈕無效 if (this.data.isInput) return //button獲取焦點后,textarea才失去焦點,contentInput有值 setTimeout(function () { if (_this.data.contentInput == '') { wx.showModal({ title: '提示', content: '請輸入內容', showCancel: false, success: function (res) { if (res.confirm) { console.log('用戶點擊確定') } } }) return } else{ app.globalData.throw=app.globalData.throw+1, wx.showModal({ title: '提示', content: '成功扔出漂流瓶!', showCancel: false, success: function (res) { if (res.confirm) { console.log('用戶點擊確定') console.log(self.data.contentInput) } } }) const db = wx.cloud.database({}); const cont = db.collection('Floating'); //數據庫集合名稱為“Floating” db.collection("Floating").count() .then(async res=>{ let totals = res.total+1; //將totals賦值為數據庫集合中記錄數加一 cont.add({ //將寫入的文本存入到數據庫中,數據id+1 data:{ 數據內容: self.data.contentInput, 數據id:totals, } }) }) return } //將文本漂流瓶上傳到leancloud // 執行 CQL 語句實現新增一個 TodoFolder 對象 //扔出漂流瓶動畫 throwBottleAnimation.call(_this); }, 50) }, }) //麥克風幀動畫 function speaking() { var _this = this; //話筒幀動畫 var i = 1; this.timer = setInterval(function () { i++; i = i % 5; _this.setData({ j: i }) }, 200); } //扔出漂流瓶動畫 function throwBottleAnimation() { this.setData({ bottle: true }) var animation = wx.createAnimation({ duration: 1500,//動畫持續時間 }) // 旋轉同時縮小 animation.translate(-150, -180).rotateZ(720).scale(0, 0).step() this.setData({ animationBottle: animation.export() }) }
首先通過以下代碼獲取到輸入的文本信息,
bindTextAreaBlur: function (e) { //console.log(e.detail.value) this.setData({ contentInput: e.detail.value }); }
之后通過.add方法將讀取到的文本存入到數據庫中,為了之后能夠隨機取出漂流瓶,設置每一條記錄的id值,該id值不會重復,遞增(獲取方法:通過.count讀取集合中記錄的數據個數,然后使其加一即是要加入的數據的id值)。
撿漂流瓶頁面:
首先能否撿到漂流瓶通過隨機函數random來決定,當產生的隨機數大於5時,無法撿到,反之則可以撿到。
而當撿到漂流瓶時,通過得到一個在1~記錄數之間的隨機數來判斷撿到的是第幾個漂流瓶,並將該漂流瓶中的文本內容輸出。
var num = Math.round(Math.random() * 9 + 1); var number; var that =this; //console.log(num); const db = wx.cloud.database({}); const cont = db.collection('Floating'); if(num>5){ app.globalData.get=app.globalData.get+1, db.collection("Floating").count() .then(async res=>{ let totals = res.total; //記錄總數 number= Math.round(Math.random() * totals + 1); //得到一個在1~totals之間的隨機數 //console.log(number) db.collection("Floating").where({ //通過檢索數據id得出撿到的是哪個漂流瓶 數據id:number, }).get({ success: function (res) { //console.log(res.data[0].數據內容) that.setData({ content:res.data[0].數據內容 //將漂流瓶的文本內容賦值給content }) } }) }) console.log(that.data.content) this.setData({ bgPng: this.data.getPngThrid, dl:this.data.dl1, content1:"漂流瓶上的內容是" }) }


var num = Math.round(Math.random() * 9 + 1);//利用隨機函數得出的變量num,來判斷是否能撿到漂流瓶 console.log(num); if(num>5){ /**wx.showModal({ title: '提示', content: '未撿到漂流瓶', showCancel: false, success: function (res) { if (res.confirm) { console.log('用戶點擊確定') } } }) return**/ this.setData({ bgPng: this.data.getPngThrid, dl:this.data.dl1 })
wxml文件:
<view >
<view>
<image src="{{bgPng}}" class="back"></image>
<view class="wb">
<text >{{dl}}</text>
</view>
</view>
<button class="bind" style="width:750rpx" bindtap="getAnswer">{{motto}}</button>
</view>
JS文件:
//get.js //獲取應用實例 var app = getApp() Page({ data: { motto:"打撈漂流瓶", bgPng:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1699162582,1738986241&fm=26&gp=0.jpg", getPngSecond: "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1602692242325&di=c3cbad90b6a86eba9f22b3391bc63fdb&imgtype=0&src=http%3A%2F%2Fdpic.tiankong.com%2Fcp%2Fmh%2FQJ6226751079.jpg",//海星 getPngThrid: "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1699162582,1738986241&fm=26&gp=0.jpg",//漂流瓶 dl1:"成功撿到漂流瓶", dl2:"未能成功撿到漂流瓶", content:"請點擊下方按鈕", content1:"" }, onLoad: function () { var _this = this; //獲取屏幕寬高 wx.getSystemInfo({ success: function (res) { } }) }, getAnswer: function (){ var num = Math.round(Math.random() * 9 + 1); var number; var that =this; //console.log(num); const db = wx.cloud.database({}); const cont = db.collection('Floating'); if(num>5){ app.globalData.get=app.globalData.get+1, db.collection("Floating").count() .then(async res=>{ let totals = res.total; //記錄總數 number= Math.round(Math.random() * totals + 1); //得到一個在1~totals之間的隨機數 //console.log(number) db.collection("Floating").where({ //通過檢索數據id得出撿到的是哪個漂流瓶 數據id:number, }).get({ success: function (res) { //console.log(res.data[0].數據內容) that.setData({ content:res.data[0].數據內容 //將漂流瓶的文本內容賦值給content }) } }) }) console.log(that.data.content) this.setData({ bgPng: this.data.getPngThrid, dl:this.data.dl1, content1:"漂流瓶上的內容是" }) } else{ this.setData({ bgPng: this.data.getPngSecond, dl:this.data.dl2, content:"", content1:"" }) } } })
我的漂流瓶界面:
利用wx:if判斷是否讀取到頭像昵稱,並顯示相應的界面。
wxml文件:
<!--mine.wxml--> <view class="container"> <view class="userinfo"> <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 獲取頭像昵稱 </button> <block wx:else> <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </block> </view> </view> <button class="plp" style="width:750rpx" bindtap="mpl"> <text class="wb">我的漂流瓶</text> </button> <button class="plp" style="width:750rpx" bindtap="plxj"> <text class="wb">漂流瓶詳解</text> </button> <button class="plp" style="width:750rpx" bindtap="user"> <text class="wb">修改個人信息</text> </button>
JS文件:
Page({ data: { motto: '登錄', userInfo: {}, hasUserInfo: false, canIUse: wx.canIUse('button.open-type.getUserInfo'), getpl:"../../pages" }, //事件處理函數 bindViewTap: function() { wx.navigateTo({ url: '../zy/zy' }) }, onLoad: function () { if (app.globalData.userInfo) { this.setData({ userInfo: app.globalData.userInfo, hasUserInfo: true }) } else if (this.data.canIUse){ // 由於 getUserInfo 是網絡請求,可能會在 Page.onLoad 之后才返回 // 所以此處加入 callback 以防止這種情況 app.userInfoReadyCallback = res => { this.setData({ userInfo: res.userInfo, hasUserInfo: true }) } } else { // 在沒有 open-type=getUserInfo 版本的兼容處理 wx.getUserInfo({ success: res => { app.globalData.userInfo = res.userInfo this.setData({ userInfo: res.userInfo, hasUserInfo: true }) } }) } }, getUserInfo: function(e) { console.log(e) app.globalData.userInfo = e.detail.userInfo this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) }, signin: function () { console.log("主頁") wx.navigateTo({ url: '../zy/zy', success: function (res) { // success }, fail: function () { // fail }, complete: function () { // complete } }) }, mpl:function(){ wx.navigateTo({ url: '../user/user', success: function (res) { // success }, fail: function () { // fail }, complete: function () { // complete } }) }, user:function(){ wx.navigateTo({ url: '../user/user', success: function (res) { // success }, fail: function () { // fail }, complete: function () { // complete } }) }, plxj:function(){ wx.navigateTo({ url: '../infor/infor', success: function (res) { // success }, fail: function () { // fail }, complete: function () { // complete } }) } })
收獲總結:
由於是第一次接觸編寫微信小程序,因此在整個開發的過程中我遇到了很多的困難,但是也在其中收獲了很多。編寫過程中遇到的各種語句錯誤,bug,與預期不符的各種界面錯誤,都讓我產生了放棄了的念頭。但是,在最后能看到自己的小程序正式出爐,也是感到十分的滿足和喜悅。通過這次的開發,讓我明白了小程序,軟件的開發,不僅僅只是編寫出正確的代碼,還需要合理且符合用戶需求的設計,只有這樣設計出的軟件才能稱得上是合格的軟件。除此之外,也明白自己在軟件開發這方面還有很多要學,要走的路還很長,因此在未來的道路上我也要砥礪前行,不忘初心。
