简易漂流瓶小程序设计(含后台)

博客班级 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,与预期不符的各种界面错误,都让我产生了放弃了的念头。但是,在最后能看到自己的小程序正式出炉,也是感到十分的满足和喜悦。通过这次的开发,让我明白了小程序,软件的开发,不仅仅只是编写出正确的代码,还需要合理且符合用户需求的设计,只有这样设计出的软件才能称得上是合格的软件。除此之外,也明白自己在软件开发这方面还有很多要学,要走的路还很长,因此在未来的道路上我也要砥砺前行,不忘初心。

 

posted @ 2020-10-18 13:56  Blank?  阅读(3829)  评论(0)    收藏  举报