簡易漂流瓶小程序設計(含后台)


博客班級 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,與預期不符的各種界面錯誤,都讓我產生了放棄了的念頭。但是,在最后能看到自己的小程序正式出爐,也是感到十分的滿足和喜悅。通過這次的開發,讓我明白了小程序,軟件的開發,不僅僅只是編寫出正確的代碼,還需要合理且符合用戶需求的設計,只有這樣設計出的軟件才能稱得上是合格的軟件。除此之外,也明白自己在軟件開發這方面還有很多要學,要走的路還很長,因此在未來的道路上我也要砥礪前行,不忘初心。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM