午夜91福利视频,午夜成人在线观看,午夜在线视频免费观看,午夜福利短视频,精品午夜成人免费视频APP

小程序模板網

微信小程序:ofo共享單車之地圖組件

發布時間(jian):2017-12-11 09:26 所屬欄目:小程序開發教程

想(xiang)學一下微信(xin)小程序(xu)(xu),發現文(wen)檔這(zhe)東西,干看真沒啥意(yi)思。所以打算自己先動手擼(lu)一個(ge)。摩(mo)拜單車有自己的(de)小程序(xu)(xu),基本功(gong)能都(dou)有,方(fang)便又(you)小巧,甚是喜愛。于是我就(jiu)萌生(sheng)了一個(ge)給ofo共享單車擼(lu)一個(ge)小程序(xu)(xu)(不知道為啥ofo沒有小程序(xu)(xu))的(de)想(xiang)法。Let's do it!

由于(yu)本文篇幅過長,影響瀏覽體驗,我(wo)對這篇文章做了(le)一下拆(chai)分(fen),修正了(le)一些錯誤。有(you)需要的(de)可以移步(bu)瀏覽 后(hou)續: 有(you)位(wei)php攻城獅(shi)根據(ju)(ju)此(ci)前端(duan)項目添加了(le)后(hou)臺數據(ju)(ju)支持(chi),詳情請(qing)轉(zhuan): //www.jianshu.com/p/8a5687a15648

先上一(yi)波效果圖:

 
1.首頁地圖頁
 
2.維修報障頁
 
3.登錄頁
 
4.錢包余額頁
 
5.充值頁
 
6.獲取了密碼頁
 
7.計費頁

1.準備工作

微信小(xiao)程(cheng)序當然屬于騰訊(xun)大(da)佬(lao)(lao)的(給大(da)佬(lao)(lao)遞茶(cha)):微信小(xiao)程(cheng)序開(kai)發(fa)(fa)者工具,騰訊(xun)開(kai)放了小(xiao)程(cheng)序個(ge)人開(kai)發(fa)(fa)平臺(tai),只需要一個(ge)微信號就可以成為小(xiao)程(cheng)序開(kai)發(fa)(fa)者了。

2.小程序頁面

 打開(kai)小程序開(kai)發者工具,用微信掃碼登錄,創建一個默認的(de)小程序。界面是醬(jiang)的(de):

 
小程序開發者工具頁面

pages文(wen)件(jian)夾下存(cun)放著小程序所有的業務(wu)頁面(mian);

index文(wen)件(jian)夾就(jiu)是一個頁面,index.wxml是頁面的結構(gou)文(wen)件(jian),類(lei)似html。

index.wxss是頁面(mian)的(de)樣式,其實就是css;index.js是頁面(mian)的(de)邏(luo)輯,數據請求與(yu)渲染都是都在這個頁面(mian)完成。

logs文件夾存放著小程(cheng)序開發日志,目前暫時(shi)用不到。

utils.js可以編寫(xie)自己的JavaScript插件。

app.js處理(li)全(quan)(quan)局的一些(xie)邏輯,比(bi)如定義全(quan)(quan)局變量存(cun)放(fang)獲取的用戶(hu)信(xin)息(xi)(xi),這樣每個(ge)頁面都(dou)可以獲取用戶(hu)信(xin)息(xi)(xi)。

app.json 是全局配置文件,比如設(she)置標題欄的背(bei)景(jing)色等。

app.wxss 存(cun)放頁面(mian)的公(gong)共(gong)樣(yang)式,如果(guo)多個頁面(mian)需要用到同一樣(yang)式,就可以寫在這(zhe)里(li)。

項目按鈕顯示預覽二維碼,用于真機調試。必須真機調試測試代碼

3.創建頁面結構

上(shang)一節已經分(fen)析了默認的文件結構(gou)以及它們(men)的功能,現在我(wo)們(men)要創建ofo小程序(xu)所需要的頁面。

  • 1.刪除pages下默認的index文件夾,logs/utils文件夾可選擇性刪除
  • 2.在與pages同級目錄下創建images文件夾,存放頁面需要用到的圖標,下載圖標
  • 3.本小程序不需要在app.js里面編寫內容,可以注釋這里面的代碼
  • 4.在app.json里,刪掉默認代碼,編寫如下代碼(app.json文件里不能有任何注釋,這里是為了描述頁面功能更直觀):
{
  "pages":[
    "pages/index/index", // 地圖頁
    "pages/warn/index",  // 車輛報障頁
    "pages/scanresult/index", // 掃碼成功頁
    "pages/billing/index", // 開始計費頁
    "pages/my/index", // 賬戶頁
    "pages/wallet/index", // 錢包頁
    "pages/charge/index", // 充值頁
    "pages/logs/logs" // 日志頁
  ],
  "window":{
    "backgroundTextStyle":"light", 
    "navigationBarBackgroundColor": "#b9dd08", // 標題欄背景色
    "navigationBarTitleText": "ofo 共享單車",  // 標題欄文字
    "navigationBarTextStyle":"black" // 標題欄文字樣式
  }
}
  • 5.app.wxss是通用樣式,先添加幾個通用樣式,以后用得到:
/**app.wxss**/
.container{
    background-color: #f2f2f2;
    height: 100vh;
}
.title{
    background-color: #f2f2f2;
    padding: 30rpx 0 30rpx 50rpx;
    font-size: 28rpx;
    color: #000;
}
.tapbar{
    display: flex;
    align-items: center;
    justify-content: space-between;
    background-color: #fff;
    padding: 40rpx;
}
.btn-charge{
    width: 90%;
    background-color: #b9dd08;
    margin: 40rpx auto 30rpx;
    text-align: center;
}

保存后(hou),你(ni)的pages文件(jian)夾下(xia)就(jiu)是這樣的界面(mian)了(在app.json下(xia)創建路徑會自動創建文件(jian)夾,賊方便)


 
頁面結構

4.編寫地圖首頁 (index文件夾)

先(xian)來回看一下效果圖


 
1.首頁地圖頁

頁面分析:

1.整頁顯示地圖,寬高占手機窗口的100%;
2.地(di)圖(tu)之上有五個按(an)(an)鈕(niu)圖(tu)標(biao)和多個黃色ofo標(biao)記(ji):定位(wei)按(an)(an)鈕(niu),立即用(yong)車按(an)(an)鈕(niu),舉報按(an)(an)鈕(niu),黃色頭像按(an)(an)鈕(niu)和位(wei)于地(di)圖(tu)中心的標(biao)記(ji)。

4.1 要在整頁顯示地圖,我們可以在index.wxml引入地圖組件:

<!--index.wxml-->
<view class="container">
  <map id="ofoMap" 
    latitude="{{latitude}}"  // 緯度
    longitude="{{longitude}}"  // 經度
    scale="{{scale}}"  // 縮放級別
    show-location/>    // 顯示帶有方向的小圓點
</view>

{{...}} 里面是數(shu)據(ju)變量,由js里的data對(dui)象(xiang)定義。

4.2 初始化數據,在index.js的data對象里添加如下代碼:

//index.js
Page({
  data: {
    scale: 18, // 縮放級別,默認18,數值在0~18之間
    latitude: 0, // 給個默認值
    longitude: 0 // 給個默認值
  },
  onLoad:function(options){
    // 頁面初始化 options為頁面跳轉所帶來的參數
  },
  onReady:function(){
    // 頁面渲染完成
  },
  onShow:function(){
    // 頁面顯示
  },
  onHide:function(){
    // 頁面隱藏
  },
  onUnload:function(){
    // 頁面關閉
  }

這(zhe)樣我們(men)(men)(men)的(de)地圖就默認中心(xin)位(wei)置(zhi)為經(jing)度(du)(du) 0,緯度(du)(du)0。當(dang)(dang)然可能在開發者工具里(li)顯示(shi)不出來(lai),莫慌!這(zhe)不是(shi)我們(men)(men)(men)想要的(de),我們(men)(men)(men)想要的(de)是(shi)我們(men)(men)(men)自己的(de)位(wei)置(zhi),所以得先(xian)獲取我們(men)(men)(men)當(dang)(dang)前所在位(wei)置(zhi)的(de)經(jing)緯度(du)(du),在index.js里(li)的(de)onLoad方法里(li)添加如下(xia)代碼:

onLoad: function(options){
  // 頁面初始化 options為頁面跳轉所帶來的參數

  // 調用wx.getLocation系統API,獲取并設置當前位置經緯度
    wx.getLocation({
      type: "gcj02", // 坐標系類型
      // 獲取經緯度成功回調
      success: (res) => { // es6 箭頭函數,可以解綁當前作用域的this指向,使得下面的this可以綁定到Page對象
        this.setData({  // 為data對象里定義的經緯度默認值設置成獲取到的真實經緯度,這樣就可以在地圖上顯示我們的真實位置
          longitude: res.longitude,
          latitude: res.latitude
        })
      }
    });
}

res是一個數據對象,它是由調用的對應API傳過來的,如果你想知道res的具體值,可以在成功回調函數里打印,然后在控制臺輸出:console.log(res)。在調用一個陌生API的時候可以用這種方法查看返回的對象數據,對處理邏輯很有幫助。

我們在地圖上(shang)顯示了我們的真(zhen)實(shi)位置,但沒有移(yi)動(dong)到中(zhong)心(xin)位置,wx.moveToLocation()函數可以把(ba)當前位置移(yi)動(dong)到地圖中(zhong)心(xin)。修改index.js:

//index.js
var app = getApp()
Page({
  data: {
    scale: 18,
    latitude: 0,
    longitude: 0
  },
// 頁面加載
  onLoad: function(options){
  // 1.頁面初始化 options為頁面跳轉所帶來的參數

  // 2.調用wx.getLocation系統API,獲取并設置當前位置經緯度
    wx.getLocation({
      type: "gcj02", // 坐標系類型
      // 獲取經緯度成功回調
      success: (res) => { // es6 箭頭函數,可以解綁當前作用域的this指向,使得下面的this可以綁定到Page對象
        this.setData({  // 為data對象里定義的經緯度默認值設置成獲取到的真實經緯度,這樣就可以在地圖上顯示我們的真實位置
          longitude: res.longitude,
          latitude: res.latitude
        })
      }
    });
}
// 頁面顯示
  onShow: function(){
    // 1.創建地圖上下文,移動當前位置到地圖中心
    this.mapCtx = wx.createMapContext("ofoMap"); // 地圖組件的id
    this.movetoPosition()
  },
// 定位函數,移動位置到地圖中心
  movetoPosition: function(){
    this.mapCtx.moveToLocation();
  }
})

這樣,頁面一顯示(shi)就(jiu)在地圖(tu)中心顯示(shi)當前位置(zhi)。

4.3 滿屏顯示地圖,在index.wxss里編寫樣式:

/**index.wxss**/
.container{
  position: relative;
  width: 100%; // 寬度占滿設備
  height: 100vh; // 高度占滿設備
}
#ofoMap{
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
}

保存刷新,整個(ge)屏幕就都(dou)顯(xian)示(shi)地圖(tu)了>_<

4.4 添加地圖上的按鈕

其(qi)實這(zhe)里的按鈕不是真正的按鈕,它們屬于地圖上的控件屬性,并且不隨(sui)著(zhu)地圖移動(dong)。這(zhe)里有一個坑(keng):

地(di)(di)圖組件屬(shu)于微(wei)信原(yuan)生組件,層(ceng)級最(zui)高,任(ren)何元(yuan)素(su)都不能在地(di)(di)圖之上顯示,即無(wu)論設置多(duo)(duo)大z-index都無(wu)法顯示。所以,要(yao)想在地(di)(di)圖上添加按鈕來滿足(zu)需求,就(jiu)要(yao)用到地(di)(di)圖控件屬(shu)性。更(geng)多(duo)(duo)地(di)(di)圖控件屬(shu)性說明看這(zhe)里

要添加(jia)地圖控(kong)件,先在(zai)地圖組件里聲明controls="...":

<!--index.wxml-->
<view class="container">
  <map id="ofoMap" 
    latitude="{{latitude}}"  // 緯度
    longitude="{{longitude}}"  // 經度
    scale="{{scale}}"  // 縮放級別
    controls="{{controls}}" // 地圖控件數組,多個控件存放在數組里
    show-location/>    // 顯示帶有方向的小圓點
</view>

然后(hou)在index.js設(she)置controls(代(dai)碼(ma)注釋還是挺多的)

//index.js
var app = getApp()
Page({
  data: {
    scale: 18,
    latitude: 0,
    longitude: 0
  },
// 頁面加載
  onLoad: function(options){
  // 1.頁面初始化 options為頁面跳轉所帶來的參數

  // 2.調用wx.getLocation系統API,獲取并設置當前位置經緯度
    ...已省略

  // 3.設置地圖控件的位置及大小,通過設備寬高定位
    wx.getSystemInfo({ // 系統API,獲取系統信息,比如設備寬高
      success: (res) => {
        this.setData({
          // 定義控件數組,可以在data對象初始化為[],也可以不初始化,取決于是否需要更好的閱讀
          controls: [{
            id: 1, // 給控件定義唯一id
            iconPath: '/images/location.png', // 控件圖標
            position: { // 控件位置
              left: 20, // 單位px
              top: res.windowHeight - 80, // 根據設備高度設置top值,可以做到在不同設備上效果一致
              width: 50, // 控件寬度/px
              height: 50 // 控件高度/px
            },
            clickable: true // 是否可點擊,默認為true,可點擊
          },
          {
            id: 2,
            iconPath: '/images/use.png',
            position: {
              left: res.windowWidth/2 - 45,
              top: res.windowHeight - 100,
              width: 90,
              height: 90
            },
            clickable: true
          },
          {
            id: 3,
            iconPath: '/images/warn.png',
            position: {
              left: res.windowWidth - 70,
              top: res.windowHeight - 80,
              width: 50,
              height: 50
            },
            clickable: true
          },
          {
            id: 4,
            iconPath: '/images/marker.png',
            position: {
              left: res.windowWidth/2 - 11,
              top: res.windowHeight/2 - 45,
              width: 22,
              height: 45
            },
            clickable: false
          },
          {
            id: 5,
            iconPath: '/images/avatar.png',
            position: {
              left: res.windowWidth - 68,
              top: res.windowHeight - 155,
              width: 45,
              height: 45
            },
            clickable: true
          }]
        })
      }
    });
}
// 頁面顯示
  onShow: function(){
    ...
  },
// 定位函數,移動位置到地圖中心
  movetoPosition: function(){
    this.mapCtx.moveToLocation();
  }
})

4.5 為地圖控件綁定事件

現在地圖上總共有四個圖標(biao)可點擊(地圖中心的標(biao)記控(kong)件(jian)不需要點擊),我們需要為每(mei)個控(kong)件(jian)綁定不同的事件(jian)以實現不同的功(gong)能:

1.點(dian)擊(ji)定(ding)位(wei)控件,觸發定(ding)位(wei)當(dang)前(qian)位(wei)置到地圖中心,因為用戶(hu)在(zai)拖動地圖,有時需(xu)要查看當(dang)前(qian)所在(zai)位(wei)置。

 2.點擊立即用車控件,調用微信內置掃碼功能(neng)。然后(hou)獲取(qu)開鎖密碼。

3.點擊舉報按鈕(niu),前往維修報障頁面。

4.點擊用戶頭像按鈕(niu),前往登(deng)錄頁面進行登(deng)錄,查看余額,充值等(deng)操作

為(wei)控(kong)件(jian)綁定(ding)事(shi)件(jian),需要在地圖控(kong)件(jian)進行聲明:bindcontroltap

<!--index.wxml-->
<view class="container">
  <map id="ofoMap" 
    latitude="{{latitude}}"  // 緯度
    longitude="{{longitude}}"  // 經度
    scale="{{scale}}"  // 縮放級別
    controls="{{controls}}" // 地圖控件數組,多個控件存放在數組里
    bindcontroltap="bindcontroltap" // 控件點擊事件
    show-location/>    // 顯示帶有方向的小圓點
</view>

注意: bindcontroltap事件會響應所有控件的點擊,所以,我們需要根據控件id來區分控件,然后響應不同的事件

在index.js添(tian)加bindcontroltap事件:

//index.js
var app = getApp()
Page({
  data: {
    scale: 18,
    latitude: 0,
    longitude: 0
  },
// 頁面加載
  onLoad: function(options){
  // 1.獲取定時器,用于判斷是否已經在計費
    this.timer = options.timer;

  // 2.調用wx.getLocation系統API,獲取并設置當前位置經緯度
    ...已省略

  // 3.設置地圖控件的位置及大小,通過設備寬高定位
    ...已省略
}
// 地圖控件點擊事件
  bindcontroltap: function(e){
    // 判斷點擊的是哪個控件 e.controlId代表控件的id,在頁面加載時的第3步設置的id
    switch(e.controlId){
      // 點擊定位控件
      case 1: this.movetoPosition();
        break;
      // 點擊立即用車,判斷當前是否正在計費,此處只需要知道是調用掃碼,后面會講到this.timer是怎么來的
      case 2: if(this.timer === "" || this.timer === undefined){
          // 沒有在計費就掃碼
          wx.scanCode({
            success: (res) => {
              // 正在獲取密碼通知
              wx.showLoading({
                title: '正在獲取密碼',
                mask: true
              })
              // 請求服務器獲取密碼和車號
              wx.request({
                url: '//www.easy-mock.com/mock/59098d007a878d73716e966f/ofodata/password',
                data: {},
                method: 'GET', 
                success: function(res){
                  // 請求密碼成功隱藏等待框
                  wx.hideLoading();
                  // 攜帶密碼和車號跳轉到密碼頁
                  wx.redirectTo({
                    url: '../scanresult/index?password=' + res.data.data.password + '&number=' + res.data.data.number,
                    success: function(res){
                      wx.showToast({
                        title: '獲取密碼成功',
                        duration: 1000
                      })
                    }
                  })           
                }
              })
            }
          })
        // 當前已經在計費就回退到計費頁
        }else{
          wx.navigateBack({
            delta: 1
          })
        }  
        break;
      // 點擊保障控件,跳轉到報障頁
      case 3: wx.navigateTo({
          url: '../warn/index'
        });
        break;
      // 點擊頭像控件,跳轉到個人中心
      case 5: wx.navigateTo({
          url: '../my/index'
        });
        break; 
      default: break;
    }
  },
// 頁面顯示
  onShow: function(){
    ...已省略
  },
// 定位函數,移動位置到地圖中心
  movetoPosition: function(){
    this.mapCtx.moveToLocation();
  }
})

這里用到的API:
掃碼API: wx.scanCode({})
顯示加載框: wx.showLoading()
隱藏加載框: wx.hideLoading()
顯示提示框: wx.showToast()
隱藏提示框: wx.hideToast()
向服務器發送請求:wx.request({})
關閉當前頁面,跳轉到指定頁面: wx.redirectTo({})
保留當前頁面,跳轉到指定頁面: wx.navigateTo({})
回退到指定頁面: wx.naivgateBack({})

查看詳細用法,查看官(guan)方API文檔(dang)

tips: 跳轉(zhuan)頁面傳(chuan)參示例

 
let num = 1;
wx.navigateTo({
    url: '../other/index?num=' + num
 });
// other頁面
onLoad: function(options){
    console.log(options.num); // 1
}

多個參數(shu)用(yong)&分(fen)隔,如 'index?num=' + num + '&text=' + 'text'

4.6 在地圖上添加單車標記makers和位置連線,還是在地圖組件里先聲明:

<!--index.wxml-->
<view class="container">
  <map id="ofoMap" 
    latitude="{{latitude}}"  // 緯度
    longitude="{{longitude}}"  // 經度
    scale="{{scale}}"  // 縮放級別
    controls="{{controls}}" // 地圖控件數組,多個控件存放在數組里
    bindcontroltap="bindcontroltap" // 控件點擊事件
    polyline="{{polyline}}"  // 位置連線
    markers="{{markers}}" // 標記數組
    bindmarkertap="bindmarkertap" // 標記點擊事件
    show-location/>    // 顯示帶有方向的小圓點
</view>

然(ran)后(hou)在(zai)index.js里定義:

//index.js
var app = getApp()
Page({
  data: {
    scale: 18,
    latitude: 0,
    longitude: 0
  },
// 頁面加載
  onLoad: function(options){
  // 1.獲取定時器,用于判斷是否已經在計費
    this.timer = options.timer;

  // 2.調用wx.getLocation系統API,獲取并設置當前位置經緯度
    ...已省略

  // 3.設置地圖控件的位置及大小,通過設備寬高定位
    ...已省略

  // 4.請求服務器,顯示附近的單車,用marker標記
    wx.request({
      url: '//www.easy-mock.com/mock/59098d007a878d73716e966f/ofodata/biyclePosition',
      data: {},
      method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
      // header: {}, // 設置請求的 header
      success: (res) => {
          this.setData({
            markers: res.data.data
          })
      }
    })
}
// 地圖控件點擊事件
  bindcontroltap: function(e){
    ...已省略
  },
// 地圖標記點擊事件,連接用戶位置和點擊的單車位置
  bindmarkertap: function(e){
    let _markers = this.data.markers; // 拿到標記數組
    let markerId = e.markerId; // 獲取點擊的標記id
    let currMaker = _markers[markerId]; // 通過id,獲取當前點擊的標記
    this.setData({
      polyline: [{
        points: [{ // 連線起點
          longitude: this.data.longitude,
          latitude: this.data.latitude
        }, { // 連線終點(當前點擊的標記)
          longitude: currMaker.longitude,
          latitude: currMaker.latitude
        }],
        color:"#FF0000DD",
        width: 1,
        dottedLine: true
      }],
      scale: 18
    })
  },
// 頁面顯示
  onShow: function(){
    ...已省略
  },
// 定位函數,移動位置到地圖中心
  movetoPosition: function(){
    this.mapCtx.moveToLocation();
  }
})

4.7 用戶拖動地圖事件

我們(men)已(yi)經為(wei)地(di)圖控(kong)件(jian)和標(biao)記響(xiang)應了不(bu)同的事(shi)件(jian),現在(zai)(zai)如(ru)果用(yong)戶拖(tuo)(tuo)動(dong)地(di)圖,我們(men)需要(yao)在(zai)(zai)拖(tuo)(tuo)動(dong)附件(jian)顯示單車,在(zai)(zai)地(di)圖組件(jian)聲明地(di)圖拖(tuo)(tuo)動(dong)事(shi)件(jian):

<!--index.wxml-->
<view class="container">
  <map id="ofoMap" 
    latitude="{{latitude}}"  // 緯度
    longitude="{{longitude}}"  // 經度
    scale="{{scale}}"  // 縮放級別
    controls="{{controls}}" // 地圖控件數組,多個控件存放在數組里
    bindcontroltap="bindcontroltap" // 控件點擊事件
    polyline="{{polyline}}"  // 位置連線
    markers="{{markers}}" // 標記數組
    bindmarkertap="bindmarkertap" // 標記點擊事件
    bindregionchange="bindregionchange" // 拖動地圖事件
    show-location/>    // 顯示帶有方向的小圓點
</view>

在index.js里實(shi)現這個事件方(fang)法:

//index.js
var app = getApp()
Page({
 data: {
   scale: 18,
   latitude: 0,
   longitude: 0
 },
// 頁面加載
 onLoad: function(options){
 // 1.獲取定時器,用于判斷是否已經在計費
   this.timer = options.timer;

 // 2.調用wx.getLocation系統API,獲取并設置當前位置經緯度
   ...已省略

 // 3.設置地圖控件的位置及大小,通過設備寬高定位
   ...已省略

 // 4.請求服務器,顯示附近的單車,用marker標記
   ...已省略
}
// 地圖控件點擊事件
 bindcontroltap: function(e){
   ...已省略
 },
// 地圖視野改變事件
 bindregionchange: function(e){
   // 拖動地圖,獲取附件單車位置
   if(e.type == "begin"){
     wx.request({
       url: '//www.easy-mock.com/mock/59098d007a878d73716e966f/ofodata/biyclePosition',
       data: {},
       method: 'GET', 
       success: (res) => {
         this.setData({
           _markers: res.data.data
         })
       }
     })
   // 停止拖動,顯示單車位置
   }else if(e.type == "end"){
       this.setData({
         markers: this.data._markers
       })
   }
 },
// 地圖標記點擊事件,連接用戶位置和點擊的單車位置
 bindmarkertap: function(e){
   ...已省略
 },
// 頁面顯示
 onShow: function(){
   ...已省略
 },
// 定位函數,移動位置到地圖中心
 movetoPosition: function(){
   this.mapCtx.moveToLocation();
 }
})

至此,首頁地圖已經完成了,接下來要編寫(xie)響應的跳轉(zhuan)頁面

5.編寫掃碼之后的獲取密碼頁(scanresult文件夾)

上(shang)一節我們為立即用(yong)車響(xiang)應了掃碼事件,掃碼成功(gong)后的頁面是醬的:


 
獲取了密碼的頁面

頁面分析

1.后臺需(xu)要拿到開(kai)鎖密碼(ma),然(ran)后顯(xian)示在頁面(mian)上

 2.我們需要(yao)一(yi)個定時器,規(gui)定多長時間(jian)用來檢查車(che)輛,這期間(jian)可(ke)以(yi)點擊回首(shou)頁去車(che)輛報障鏈接(jie),當然也就取消了本次(ci)掃碼。

3.檢查時(shi)長完成后,自動跳轉到計費頁面

1.頁(ye)面布局

<!--pages/scanresult/index.wxml-->
<view class="container">
    <view class="password-title">
        <text>開鎖密碼</text>
    </view>
    <view class="password-content">
        <text>{{password}}</text>
    </view>
    <view class="tips">
        <text>請使用密碼解鎖,{{time}}s后開始計費</text>
        <view class="tips-action" bindtap="moveToWarn">
            車輛有問題?
            <text class="tips-href">回首頁去車輛報障</text>
        </view>
    </view>
</view>

2.頁(ye)面樣(yang)式

.container{
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    background-color: #fff;
}
.password-title,.tips{
    width: 100%;
    flex: 1;
    text-align: center;
    padding: 60rpx 0;
}
.password-content{
    width: 100%;
    flex: 8;
    text-align: center;
    font-size: 240rpx;
    font-weight: 900;
}
.tips{
    font-size: 32rpx;
}
.tips .tips-action{
    margin-top: 20rpx;  
}
.tips .tips-href{
    color: #b9dd08
}

3.頁面數據邏輯

// pages/scanresult/index.js
Page({
  data:{
    time: 9 // 默認計時時長,這里設短一點,用于調試,ofo app是90s
  },
// 頁面加載
  onLoad:function(options){
    // 獲取解鎖密碼
    this.setData({
      password: options.password
    })
    // 設置初始計時秒數
    let time = 9;
    // 開始定時器
    this.timer = setInterval(() => {
      this.setData({
        time: -- time
      });
      // 讀完秒后攜帶單車號碼跳轉到計費頁
      if(time = 0){
        clearInterval(this.timer)
        wx.redirectTo({
          url: '../billing/index?number=' + options.number
        })
      }
    },1000)
  },
// 點擊去首頁報障
  moveToWarn: function(){
    // 清除定時器
    clearInterval(this.timer)
    wx.redirectTo({
      url: '../index/index'
    })
  }
})

注意:這里的this.timer不會被傳參到pages/index/index.js里的onload函數里,被傳參到首頁的定時器是計費頁的定時器,后面會講到

 tips: onload函(han)數參數說明: options的值是掃碼(ma)成(cheng)功(gong)后請求服(fu)務(wu)器獲取的單(dan)車編號和開(kai)鎖密碼(ma)

// pages/index/index.js
// 點擊立即用車,判斷當前是否正在計費
      case 2: if(this.timer === "" || this.timer === undefined){
          // 沒有在計費就掃碼
          wx.scanCode({
            success: (res) => {
              // 正在獲取密碼通知
              wx.showLoading({
                title: '正在獲取密碼',
                mask: true
              })
              // 請求服務器獲取密碼和車號
              wx.request({
                url: '//www.easy-mock.com/mock/59098d007a878d73716e966f/ofodata/password',
                data: {},
                method: 'GET', 
                success: function(res){
                  // 請求密碼成功隱藏等待框
                  wx.hideLoading();
                  // 攜帶密碼和車號跳轉到密碼頁
                  wx.redirectTo({
                    url: '../scanresult/index?password=' + res.data.data.password + '&number=' + res.data.data.number,
                    success: function(res){
                      wx.showToast({
                        title: '獲取密碼成功',
                        duration: 1000
                      })
                    }
                  })           
                }
              })
            }
          })
        // 當前已經在計費就回退到計費頁
        }else{
          wx.navigateBack({
            delta: 1
          })
        }  
        break;
// pages/scanresult/index.js
onload: function(options){
  console.log(options); // { password: "", number: "" }
}

6.編寫計費頁(billing文件夾)

上(shang)節中(zhong)我們設置了(le)計時器完成(cheng)后,跳轉到計費頁,它是醬的(de):


 
計費頁

頁面分析:

1.后臺需要拿到單(dan)車(che)編號(hao),并(bing)顯示在頁面上(shang)

2.我們需要(yao)一個(ge)計時器(qi)累加騎行事件用(yong)來(lai)計費(fei),而且可以顯示最大單位是小時

3.兩個按鈕:結(jie)束騎行,回到(dao)地圖 。其中(zhong),點(dian)擊(ji)結(jie)束騎行,關(guan)閉計(ji)時(shi)器(qi),根據累計(ji)時(shi)長計(ji)費;點(dian)擊(ji)回到(dao)地圖,如果(guo)計(ji)時(shi)器(qi)已經關(guan)閉了,就關(guan)閉計(ji)費頁,跳轉到(dao)地圖。如果(guo)計(ji)時(shi)器(qi)仍然(ran)在(zai)計(ji)時(shi),保留當(dang)前頁面,跳轉到(dao)地圖。

4.點擊回到地(di)圖會把計(ji)(ji)時器狀態帶給首(shou)頁,首(shou)頁做出判斷,判定再(zai)次點擊立(li)即(ji)用車響(xiang)應合(he)理邏輯(已經在(zai)計(ji)(ji)費,不能重(zhong)復掃碼。已經停止計(ji)(ji)費了,需要重(zhong)新掃碼)

1.頁面結構

<!--pages/billing/index.wxml-->
<view class="container">
    <view class="number">
        <text>當前單車編號: {{number}}</text>
    </view>
    <view class="time">
        <view class="time-title">
            <text>{{billing}}</text>
        </view>
        <view class="time-content">
            <text>{{hours}}:{{minuters}}:{{seconds}}</text>
        </view>
    </view>

    <view class="endride">
        <button type="warn" disabled="{{disabled}}" bindtap="endRide">結束騎行</button>
        <button type="primary" bindtap="moveToIndex">回到地圖</button>
    </view>
</view>

2.頁面(mian)樣式

.container{
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    background-color: #fff;
}
.number,.endride{
    padding: 60rpx 0;
    flex: 2;
    width: 100%;
    text-align: center;
}
.time{
    text-align: center;
    width: 100%;
    flex: 6;
}
.time .time-content{
    font-size: 100rpx;
}
.endride button{
    width: 90%;
    margin-top: 40rpx;
}

3.頁(ye)面數據邏(luo)輯

// pages/billing/index.js
Page({
  data:{
    hours: 0,
    minuters: 0,
    seconds: 0,
    billing: "正在計費"
  },
// 頁面加載
  onLoad:function(options){
    // 獲取車牌號,設置定時器
    this.setData({
      number: options.number,
      timer: this.timer
    })
    // 初始化計時器
    let s = 0;
    let m = 0;
    let h = 0;
    // 計時開始
    this.timer = setInterval(() => {
      this.setData({
        seconds: s++
      })
      if(s == 60){
        s = 0;
        m++;
        setTimeout(() => {         
          this.setData({
            minuters: m
          });
        },1000)      
        if(m == 60){
          m = 0;
          h++
          setTimeout(() => {         
            this.setData({
              hours: h
            });
          },1000)
        }
      };
    },1000)  
  },
// 結束騎行,清除定時器
  endRide: function(){
    clearInterval(this.timer);
    this.timer = "";
    this.setData({
      billing: "本次騎行耗時",
      disabled: true
    })
  },
// 攜帶定時器狀態回到地圖
  moveToIndex: function(){
    // 如果定時器為空
    if(this.timer == ""){
      // 關閉計費頁跳到地圖
      wx.redirectTo({
        url: '../index/index'
      })
    // 保留計費頁跳到地圖
    }else{
      wx.navigateTo({
        url: '../index/index?timer=' + this.timer
      })
    }
  }
})

頁面分析的第4步,主要實現在moveToIndex函數里。結束騎行之后,設置定時器值為空,在點擊回到地圖時判斷計時器的狀態(值是否為空)。如果為空,關閉計費頁,結束本次騎行。如果不為空,攜帶定時器狀態跳轉到首頁,首頁立即用車點擊事件就會對傳過來的參數(計時器狀態)響應合理邏輯。

7.編寫維修報障頁(warn文件夾)

點擊舉報控件,頁面是醬的(de):


 
維修報障頁1
 
維修報障頁2

頁面分析:

1.頁(ye)面可以(yi)勾選故(gu)障類型(xing),所以(yi)需要(yao)(yao)用(yong)到復選框組件;可以(yi)選擇(ze)上傳或拍攝圖(tu)片,所以(yi)要(yao)(yao)使用(yong)wx.chooseImage({})選取圖(tu)片API;可以(yi)輸入(ru)(ru)車牌號好(hao)備注,所以(yi)需要(yao)(yao)使用(yong)input輸入(ru)(ru)組件。

2.勾選類型(xing),選擇(ze)圖片,輸入備(bei)注信息完成后,后臺需要獲取這些輸入的數據提交(jiao)到(dao)服務器以獲得反饋(kui)。

3.必(bi)須勾選類型和(he)選擇周圍(wei)環境圖(tu)片才能提交,否則彈窗(chuang)提示。可(ke)以(yi)選擇多(duo)張圖(tu)片,也可(ke)以(yi)取消(xiao)選擇的(de)圖(tu)片。

1.頁面結構(gou)

<!--pages/warn/index.wxml-->
<view class="container">
    <view class="choose">
        <view class="title">請選擇故障類型</view> 
        <checkbox-group bindchange="checkboxChange" class="choose-grids">
            <!-- itemsValue是data對象里定義的數組,item代表數組的每一項,此處語法為循環輸出數組的每一項并渲染到每一個復選框。下面還有類似語法 -->
            <block wx:for="{{itemsValue}}" wx:key="{{item}}">
                <view class="grid">
                    <checkbox value="{{item.value}}" checked="{{item.checked}}" color="{{item.color}}" />{{item.value}}
                </view>
            </block>
        </checkbox-group>        
    </view>
    <view class="action">
        <view class="title">拍攝單車周圍環境,便于維修師傅找車</view>
        <view class="action-photo">
        <block wx:for="{{picUrls}}" wx:key="{{item}}" wx:index="{{index}}">
            <image src="{{item}}"><icon type="cancel" data-index="{{index}}" color="red" size="18" class ="del" bindtap="delPic" /></image>
        </block>
            <text class="add" bindtap="bindCamera">{{actionText}}</text>
        </view>
        <view class="action-input">
            <input bindinput="numberChange" name="number" placeholder="車牌號(車牌損壞不用填)" />
            <input bindinput="descChange" name="desc" placeholder="備注" />            
        </view>
        <view class="action-submit">
            <button class="submit-btn" type="default" loading="{{loading}}" bindtap="formSubmit" style="background-color: {{btnBgc}}">提交</button>
        </view>
    </view>
</view>

2.頁面(mian)樣式

/* pages/wallet/index.wxss */
.choose{
    background-color: #fff;
}
.choose-grids{
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    padding: 50rpx;
}
.choose-grids .grid{
    width: 45%;
    height: 100rpx;
    margin-top: 36rpx;
    border-radius: 6rpx;
    line-height: 100rpx;
    text-align: center;
    border: 2rpx solid #b9dd08;
}
.choose-grids .grid:first-child,
.choose-grids .grid:nth-of-type(2){
    margin-top: 0;
}
.action .action-photo{
    background-color: #fff;
    padding: 40rpx 0px 40rpx 50rpx;
}
.action .action-photo image{
    position: relative;
    display: inline-block;
    width: 120rpx;
    height: 120rpx;
    overflow: visible;
    margin-left: 25rpx;
}
.action .action-photo image icon.del{
    display: block;
    position: absolute;
    top: -20rpx;
    right: -20rpx;
}
.action .action-photo text.add{
    display: inline-block;
    width: 120rpx;
    height: 120rpx;
    line-height: 120rpx;
    text-align: center;
    font-size: 24rpx;
    color: #ccc;
    border: 2rpx dotted #ccc;
    margin-left: 25rpx;
    vertical-align: top;
}
.action .action-input{
    padding-left: 50rpx;
    margin-top: 30rpx;
    background-color: #fff;
}
.action .action-input input{
    width: 90%;
    padding-top: 40rpx;
    padding-bottom: 40rpx;
}
.action .action-input input:first-child{
    border-bottom: 2rpx solid #ccc;
    padding-bottom: 20rpx;
}
.action .action-input input:last-child{
    padding-top: 20rpx;
}
.action .action-submit{
    padding: 40rpx 40rpx;
    background-color: #f2f2f2;
}

3.頁(ye)面數據(ju)邏(luo)輯

// pages/wallet/index.js
Page({
  data:{
    // 故障車周圍環境圖路徑數組
    picUrls: [],
    // 故障車編號和備注
    inputValue: {
      num: 0,
      desc: ""
    },
    // 故障類型數組
    checkboxValue: [],
    // 選取圖片提示
    actionText: "拍照/相冊",
    // 提交按鈕的背景色,未勾選類型時無顏色
    btnBgc: "",
    // 復選框的value,此處預定義,然后循環渲染到頁面
    itemsValue: [
      {
        checked: false,
        value: "私鎖私用",
        color: "#b9dd08"
      },
      {
        checked: false,
        value: "車牌缺損",
        color: "#b9dd08"
      },
      {
        checked: false,
        value: "輪胎壞了",
        color: "#b9dd08"
      },
      {
        checked: false,
        value: "車鎖壞了",
        color: "#b9dd08"
      },
      {
        checked: false,
        value: "違規亂停",
        color: "#b9dd08"
      },
      {
        checked: false,
        value: "密碼不對",
        color: "#b9dd08"
      },
      {
        checked: false,
        value: "剎車壞了",
        color: "#b9dd08"
      },
      {
        checked: false,
        value: "其他故障",
        color: "#b9dd08"
      }
    ]
  },
// 頁面加載
  onLoad:function(options){
    wx.setNavigationBarTitle({
      title: '報障維修'
    })
  },
// 勾選故障類型,獲取類型值存入checkboxValue
  checkboxChange: function(e){
    let _values = e.detail.value;
    if(_values.length == 0){
      this.setData({
        btnBgc: ""
      })
    }else{
      this.setData({
        checkboxValue: _values,
        btnBgc: "#b9dd08"
      })
    }   
  },
// 輸入單車編號,存入inputValue
  numberChange: function(e){
    this.setData({
      inputValue: {
        num: e.detail.value,
        desc: this.data.inputValue.desc
      }
    })
  },
// 輸入備注,存入inputValue
  descChange: function(e){
    this.setData({
      inputValue: {
        num: this.data.inputValue.num,
        desc: e.detail.value
      }
    })
  },
// 提交到服務器
  formSubmit: function(e){
    if(this.data.picUrls.length > 0 && this.data.checkboxValue.length> 0){
      wx.request({
        url: '//www.easy-mock.com/mock/59098d007a878d73716e966f/ofodata/msg',
        data: {
          // picUrls: this.data.picUrls,
          // inputValue: this.data.inputValue,
          // checkboxValue: this.data.checkboxValue
        },
        method: 'get', // POST
        // header: {}, // 設置請求的 header
        success: function(res){
          wx.showToast({
            title: res.data.data.msg,
            icon: 'success',
            duration: 2000
          })
        }
      })
    }else{
      wx.showModal({
        title: "請填寫反饋信息",
        content: '看什么看,趕快填反饋信息,削你啊',
        confirmText: "我我我填",
        cancelText: "勞資不填",
        success: (res) => {
          if(res.confirm){
            // 繼續填
          }else{
            console.log("back")
            wx.navigateBack({
              delta: 1 // 回退前 delta(默認為1) 頁面
            })
          }
        }
      })
    }
    
  },
// 選擇故障車周圍環境圖 拍照或選擇相冊
  bindCamera: function(){
    wx.chooseImage({
      count: 4, 
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'], 
      success: (res) => {
        let tfps = res.tempFilePaths;
        let _picUrls = this.data.picUrls;
        for(let item of tfps){
          _picUrls.push(item);
          this.setData({
            picUrls: _picUrls,
            actionText: "+"
          });
        }
      }
    })
  },
// 刪除選擇的故障車周圍環境圖
  delPic: function(e){
    let index = e.target.dataset.index;
    let _picUrls = this.data.picUrls;
    _picUrls.splice(index,1);
    this.setData({
      picUrls: _picUrls
    })
  }
})

注意: 這里選擇的圖片,路徑為本地路徑,如果要上傳到服務器,需要調用API上傳圖片而不是上傳本地路徑。即不能把picUrls數組上傳到服務器。

8.編寫登錄/未登錄頁(my文件夾)

點擊頭像控件,未登錄,頁面是醬的

 
未登錄頁

點擊(ji)頭像控件,已登錄,頁面是醬的


 
登錄頁

頁面分析

1.個人(ren)中(zhong)心頁有兩(liang)種狀態,即未登錄和已登錄,所以要求數據驅動頁面(mian)表現形(xing)式(shi)

2.點擊登錄(lu)/退出登錄(lu)按鈕(niu)需要響(xiang)應合理邏輯,并改變按鈕(niu)樣式

3.只有登錄(lu)狀態下(xia)才會顯示我的(de)錢(qian)包按鈕(niu)

1.頁面結構(wx:if 是(shi)條件語句)

<!--pages/my/index.wxml-->
<view class="container">
    <view class="user-info">
    <!-- 用戶未登錄就沒有頭像-->
    <block wx:if="{{userInfo.avatarUrl != ''}}">
        <image src="{{userInfo.avatarUrl}}"></image>
    </block>
        <text>{{userInfo.nickName}}</text>
    </view>
    <!-- 用戶未登錄就沒有錢包按鈕-->
    <block wx:if="{{userInfo.avatarUrl != ''}}">
    <view class="my-wallet tapbar" bindtap="movetoWallet">
        <text>我的錢包</text>
        <text>></text>
    </view>
    </block>
    <button bindtap="bindAction" class="btn-login" hover-class="gray" type="{{bType}}" >{{actionText}}</button>
</view>

2.頁面樣式

/* pages/my/index.wxss */
.user-info{
    background-color: #fff;
    padding-top: 60rpx;
}
.user-info image{
    display: block;
    width: 180rpx;
    height: 180rpx;
    border-radius: 50%;
    margin: 0 auto 40rpx;
    box-shadow: 0 0 20rpx rgba(0,0,0,.2)
}
.user-info text{
    display: block;
    text-align: center;
    padding: 30rpx 0;
    margin-bottom: 30rpx;
}
.btn-login{
    position: absolute;
    bottom: 60rpx;
    width: 90%;
    left: 50%;
    margin-left: -45%;
}
.gray{
    background-color: #ccc;
}

3.頁面數據邏輯

// pages/my/index.js
Page({
  data:{
    // 用戶信息
    userInfo: {
      avatarUrl: "",
      nickName: "未登錄"
    },
    bType: "primary", // 按鈕類型
    actionText: "登錄", // 按鈕文字提示
    lock: false //登錄按鈕狀態,false表示未登錄
  },
// 頁面加載
  onLoad:function(){
    // 設置本頁導航標題
    wx.setNavigationBarTitle({
      title: '個人中心'
    })
    // 獲取本地數據-用戶信息
    wx.getStorage({
      key: 'userInfo',
      // 能獲取到則顯示用戶信息,并保持登錄狀態,不能就什么也不做
      success: (res) => {
        wx.hideLoading();
        this.setData({
          userInfo: {
            avatarUrl: res.data.userInfo.avatarUrl,
            nickName: res.data.userInfo.nickName
          },
          bType: res.data.bType,
          actionText: res.data.actionText,
          lock: true
        })
      }
    });
  },
// 登錄或退出登錄按鈕點擊事件
  bindAction: function(){
    this.data.lock = !this.data.lock
    // 如果沒有登錄,登錄按鈕操作
    if(this.data.lock){
      wx.showLoading({
        title: "正在登錄"
      });
      wx.login({
        success: (res) => {
          wx.hideLoading();
          wx.getUserInfo({
            withCredentials: false,
            success: (res) => {
              this.setData({
                userInfo: {
                  avatarUrl: res.userInfo.avatarUrl,
                  nickName: res.userInfo.nickName
                },
                bType: "warn",
                actionText: "退出登錄"
              });
              // 存儲用戶信息到本地
              wx.setStorage({
                key: 'userInfo',
                data: {
                  userInfo: {
                    avatarUrl: res.userInfo.avatarUrl,
                    nickName: res.userInfo.nickName
                  },
                  bType: "warn",
                  actionText: "退出登錄"
                },
                success: function(res){
                  console.log("存儲成功")
                }
              })
            }     
          })
        }
      })
    // 如果已經登錄,退出登錄按鈕操作     
    }else{
      wx.showModal({
        title: "確認退出?",
        content: "退出后將不能使用ofo",
        success: (res) => {
          if(res.confirm){
            console.log("確定")
            // 退出登錄則移除本地用戶信息
            wx.removeStorageSync('userInfo')
            this.setData({
              userInfo: {
                avatarUrl: "",
                nickName: "未登錄"
              },
              bType: "primary",
              actionText: "登錄"
            })
          }else {
            console.log("cancel")
            this.setData({
              lock: true
            })
          }
        }
      })
    }   
  },
// 跳轉至錢包
  movetoWallet: function(){
    wx.navigateTo({
      url: '../wallet/index'
    })
  }
})

我們將用戶信息使用wx.setStorage({})和wx.getStorage({})這兩個API來設置和獲取本地存儲,用于模擬維護用戶登錄狀態。真實情況下需要使用session

9.編寫我的錢包頁

假設用戶已登錄,點擊錢包,頁面是醬的:


 
錢包余額頁

頁面分析

1.需(xu)要獲(huo)取(qu)錢包余額數據(ju)并(bing)顯(xian)示在(zai)頁面上,充(chong)值(zhi)后數據(ju)會自動更新(xin)

2.其他可點擊按鈕(niu)分別顯(xian)示對應的模態框,因為(wei)微信只允許五(wu)個頁面層級(ji),避(bi)免(mian)過多頁面層級(ji)造成用(yong)戶(hu)迷失。

1.頁面結構

<!--pages/wallet/index.wxml-->
<view class="container">
    <view class="overage">
        <view>
            <text class="overage-header">我的余額(元)</text>
        </view>
        <view>
            <text class="overage-amount">{{overage}}</text>
        </view>
        <view>
            <text bindtap="overageDesc" class="overage-desc">余額說明</text>
        </view>       
    </view>
    <button bindtap="movetoCharge" class="btn-charge">充值</button>
    <view bindtap="showTicket" class="my-ticket tapbar">
        <text>我的用車券</text>
        <text><text class="c-g">{{ticket}}張</text>></text>
    </view>
    <view bindtap="showDeposit" class="my-deposit tapbar">
        <text>我的押金</text>
        <text><text class="c-y">99元,押金退款</text>></text>
    </view>
    <view bindtap="showInvcode" class="my-invcode tapbar">
        <text>關于ofo</text>
        <text>></text>
    </view>
</view>

2.頁面樣式

/* pages/wallet/index.wxss */
.overage{
    background-color: #fff;
    padding: 40rpx 0;
    text-align: center;
}
.overage-header{
    font-size: 24rpx;
}
.overage-amount{
    display: inline-block;
    padding: 20rpx 0;
    font-size: 100rpx;
    font-weight: 700;
}
.overage-desc{
    padding: 10rpx 30rpx;
    font-size: 24rpx;
    border-radius: 40rpx;
    border: 1px solid #666;
}
.my-deposit{
    margin-top: 2rpx;
}
.my-invcode{
    margin-top: 40rpx;
}
.c-y{
    color: #b9dd08;
    padding-top: -5rpx;
    padding-right: 10rpx;
}
.c-g{
    padding-top: -5rpx;
    padding-right: 10rpx;
}

3.頁面數據邏輯(ji)

// pages/wallet/index.js
Page({
  data:{
    overage: 0,
    ticket: 0
  },
// 頁面加載
  onLoad:function(options){
     wx.setNavigationBarTitle({
       title: '我的錢包'
     })
  },
// 頁面加載完成,更新本地存儲的overage
  onReady:function(){
     wx.getStorage({
      key: 'overage',
      success: (res) => {
        this.setData({
          overage: res.data.overage
        })
      }
    })
  },
// 頁面顯示完成,獲取本地存儲的overage
  onShow:function(){
    wx.getStorage({
      key: 'overage',
      success: (res) => {
        this.setData({
          overage: res.data.overage
        })
      }
    }) 
  },
// 余額說明
  overageDesc: function(){
    wx.showModal({
      title: "",
      content: "充值余額0.00元+活動贈送余額0.00元",
      showCancel: false,
      confirmText: "我知道了",
    })
  },
// 跳轉到充值頁面
  movetoCharge: function(){
    // 關閉當前頁面,跳轉到指定頁面,返回時將不會回到當前頁面
    wx.redirectTo({
      url: '../charge/index'
    })
  },
// 用車券
  showTicket: function(){
    wx.showModal({
      title: "",
      content: "你沒有用車券了",
      showCancel: false,
      confirmText: "好吧",
    })
  },
// 押金退還
  showDeposit: function(){
    wx.showModal({
      title: "",
      content: "押金會立即退回,退款后,您將不能使用ofo共享單車確認要進行此退款嗎?",
      cancelText: "繼續使用",
      cancelColor: "#b9dd08",
      confirmText: "押金退款",
      confirmColor: "#ccc",
      success: (res) => {
        if(res.confirm){
          wx.showToast({
            title: "退款成功",
            icon: "success",
            duration: 2000
          })
        }
      }
    })
  },
// 關于ofo
  showInvcode: function(){
    wx.showModal({
      title: "ofo共享單車",
      content: "微信服務號:ofobike,網址:m.ofo.so",
      showCancel: false,
      confirmText: "玩的6"
    })
  }
})

我們將金額信息使用wx.setStorage({})和wx.getStorage({})這兩個API來設置和獲取本地存儲,用于模擬充值邏輯。
設置本地存儲API官方文檔

10.編寫充值頁面(charge文件夾)

點擊充值按鈕,頁面(mian)是醬的


 
充值頁

頁面分析

1.輸入(ru)金額,存儲在data對象里,點擊(ji)充(chong)值(zhi)后,設置本(ben)地金額數(shu)據

2.點(dian)擊(ji)充值按(an)鈕后自動跳轉到錢包頁。

1.頁面(mian)結(jie)構

<!--pages/charge/index.wxml-->
<view class="container">
    <view class="title">請輸入充值金額</view>
    <view class="input-box">
        <input bindinput="bindInput" />
    </view>
    <button bindtap="charge" class="btn-charge">充值</button>
</view>

2.頁面(mian)樣(yang)式

/* pages/charge/index.wxss */
.input-box{
    background-color: #fff;
    margin: 0 auto;
    padding: 20rpx 0;
    border-radius: 10rpx;
    width: 90%;

}
.input-box input{
    width: 100%;
    height: 100%;
    text-align: center;
}

3.頁面數據邏輯

// pages/charge/index.js
Page({
  data:{
    inputValue: 0
  },
// 頁面加載
  onLoad:function(options){
    wx.setNavigationBarTitle({
      title: '充值'
    })
  },
// 存儲輸入的充值金額
  bindInput: function(res){
    this.setData({
      inputValue: res.detail.value
    })  
  },
// 充值
  charge: function(){
    // 必須輸入大于0的數字
    if(parseInt(this.data.inputValue) <= 0 || isNaN(this.data.inputValue)){
      wx.showModal({
        title: "警告",
        content: "咱是不是還得給你錢?!!",
        showCancel: false,
        confirmText: "不不不不"
      })
    }else{
      wx.redirectTo({
        url: '../wallet/index',
        success: function(res){
          wx.showToast({
            title: "充值成功",
            icon: "success",
            duration: 2000
          })
        }
      })
    }
  },
// 頁面銷毀,更新本地金額,(累加)
  onUnload:function(){
    wx.getStorage({
      key: 'overage',
      success: (res) => {
        wx.setStorage({
          key: 'overage',
          data: {
            overage: parseInt(this.data.inputValue) + parseInt(res.data.overage)
          }
        })
      },
      // 如果沒有本地金額,則設置本地金額
      fail: (res) => {
        wx.setStorage({
          key: 'overage',
          data: {
            overage: parseInt(this.data.inputValue)
          },
        })
      }
    }) 
  }
})

充值頁面關閉時更新本地金額數據,所以需要在unLoad事件里執行

擴展:使用easy-mock偽造數據

小程序多次請求了服務器“發送/接受”數據,其實這里使用了easy-mock這個網站偽造的數據。
easy-mock可以作為前端開發的偽后端,自己構造數據來測試前端代碼。方便又快捷。官網戳這里。
比如我們這個小程序用到了后端api接口
1.提交報障信息的反饋
2.單車編號和解鎖密碼
3.單車經(jing)緯度

結語

到這里,ofo小程序的制作就到了尾聲了。開篇我們創建了多個頁面,然后一個一個頁面從頁面分析,到完成數據邏輯,分別響應著不同的業務邏輯,有的頁面與頁面之間有數據往來,我們就通過跳轉頁面傳參或設置本地存儲來將它們建立起聯系,環環相扣,構建起了整個小程序的基本功能。
通過這個小程序,我們發現文檔提供的API在不知不覺中已經失去了它的神秘感,它們就是不同的工具,為小程序實現業務請求搭建肢體骨架。
源碼在我的github主頁上,有需要的歡迎fork



作者:這昵稱好帥嘞
鏈接://www.jianshu.com/p/3f9b78c68887
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


易優小程序(企業版)+靈活api+前后代碼(ma)開源 碼云倉庫:
本文地址://www.jinyoudianli.com/wxmini/doc/course/18130.html 復制鏈接 如需定制請聯系易(yi)優客(ke)服咨(zi)詢:

工作日 8:30-12:00 14:30-18:00
周六及部分節假日提供(gong)值班(ban)服務

易小(xiao)優
轉(zhuan)人工 ×