初嘗微信小程式開發與實踐經驗分享

小賣鋪的老爺爺發表於2018-10-22

一個java程式設計師最不務正業的一次分享了。

小程式的火熱相信不用我多說了,年初的時候老婆去浦東某達面試,甚至都被問有沒有小程式測試經驗。儼然小程式成為了網際網路公司自PC,WAP,安卓,IOS之後又一不可或缺的入口。正好這段時間公司也在做一款小程式,於是順便也學習了一把。當然因為我是一個javaer,自然是以後端的視角來談談,和前端的同學肯定還是比不上的。

學習小程式,我認為對於後端同學還是比較有優勢的,因為後端同學對於HTML,CSS以及JS這些前端基本知識還是有所涉獵的,而前端的同學對於後端可能就沒那麼瞭解了。接下來,以我的實踐經歷來簡單聊一聊小程式,算是總結也算是個分享。

小程式用來做什麼?

“觸手可及”,“用完即走”。感覺這兩個詞把小程式的特點描述的真的是淋漓盡致。以微信的使用者量,小程式免去了使用者還需安裝APP的繁瑣。而且用完之後,無需刻意退出,直接離開即可,當下次某個時間點在想起來,重新翻出來就行了。這對很多行業來說可能是顛覆性的。以我個人的觀點來看,小程式適合做一些業務簡單,效能要求不高,使用頻率相對較低的應用。比如像垂直電商行業就是典型的受益者,自媒體電商,生鮮電商,如果讓使用者去下載一個這樣的APP成本是很大的,而使用小程式確悄然的避免了拉新客的難題。又比如我自己,如果我把自己的部落格做成了一個APP,相信幾乎不會有同學去下載,而使用小程式卻偶爾還會有些同學會點進來看看的,哈哈。

入門小程式

首先開發小程式,需要一個專門的工具【微信開發者工具】,這個大家可以直接到微信公眾平臺下載。

接下來我們首先新建個快速啟動模板看一下,如果你有註冊賬號有appid的可以填入,沒有的話也沒關係。點選圖中小程式即可使用測試賬號。

如上圖,進入後即可看到這些檔案。

可以說一個簡單的小程式只有這些了。

  • app.js 主要是全域性公共的js方法宣告及呼叫所在的檔案
  • app.json 是小程式全域性的配置檔案,所以有的頁面都在要此註冊,不然不允許訪問
  • app.wxss 是小程式全域性的css檔案
  • pages下是對應著所有頁面,每個頁面,可以新增四種型別的檔案,.json,.wxss,.wxml,.js

另外在說下這四種型別的檔案,小程式pages下面基本上每個資料夾相當於一個頁面,每個資料夾下面有四種命名相同但型別不同的檔案,這四種構成了頁面的全部。

  • .json 字尾的 JSON 配置檔案
  • .wxml 字尾的 WXML 模板檔案,類似web開發的html
  • .wxss 字尾的 WXSS 樣式檔案,類似web開發的css
  • .js 字尾的 JS 指令碼邏輯檔案,它就是一個js啊,不過小程式的js不能操作dom,是基於資料繫結的哦

然後我們在看下js檔案的構成,註釋很清晰:

Page({

  /**
   * 頁面的初始資料
   */
  data: {
    
  },

  /**
   * 生命週期函式--監聽頁面載入
   */
  onLoad: function (options) {
    
  },

  /**
   * 生命週期函式--監聽頁面初次渲染完成
   */
  onReady: function () {
    
  },

  /**
   * 生命週期函式--監聽頁面顯示
   */
  onShow: function () {
    
  },

  /**
   * 生命週期函式--監聽頁面隱藏
   */
  onHide: function () {
    
  },

  /**
   * 生命週期函式--監聽頁面解除安裝
   */
  onUnload: function () {
    
  },

  /**
   * 頁面相關事件處理函式--監聽使用者下拉動作
   */
  onPullDownRefresh: function () {
    
  },

  /**
   * 頁面上拉觸底事件的處理函式
   */
  onReachBottom: function () {
    
  },

  /**
   * 使用者點選右上角分享
   */
  onShareAppMessage: function () {
    
  }
})複製程式碼

瞭解了這些基本上小程式開發就沒問題了,其他就剩翻文件了。這裡我建議把文件當成字典來讀,讀完簡易教程和框架後,其他需要什麼來查什麼就行了,沒必要像教科書一樣一字不落的全看完。

因為微信開發者工具還比較初始,之前每建一個頁面,我都是先建一個資料夾,然後在分別把四個檔案建好。這裡我介紹個小技巧,大家可以首先將要新建的頁面註冊進app.json,這時候工具會自動把資料夾和四種檔案給你建好。說實話很奇怪,這種方法在官方文件上我並沒有看到,不知道是我眼花還是官方真的沒有寫。

{
  "pages":[
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"black"
  }
}複製程式碼

再說下頁面的註冊,當我們在app.json檔案中註冊的時候,【pages/index/index】會將該頁面下index.xx的四種檔案載入進來,而不必一個個寫了。還有就是資料夾名字和檔名是可以不同的,比如【pages/index/launch】會將index資料夾下所有的launch檔案載入。但是建議還是一樣把,不然看著挺彆扭的。

最後在多說句,小程式的域名白名單問題,我發現很多同學不知道,包括身邊的同事,一直還在用內網穿透來開發。

首先小程式對應用請求的域名是有限制的。

  1. 請求的域名必須在後臺配置,非配置域名無法請求成功。
  2. 域名協議必須是https的,如果是http請求也是會失敗的

當然,這是對線上版本來說。如果是我們本地開發,小程式提供了一個很人性化的功能。可以忽略這個限制,甚至你可以直接請求本地的IP地址+埠號,而不必使用繁瑣的內網穿透的方式了。

具體操作方式就是在微信開發者工具中,點選【設定】-【專案設定】-【勾選】不校驗合法域名、web-view(業務域名)、TLS 版本以及 HTTPS 證照 即可,如下圖

下面就結合我的實踐小程式來簡單聊一聊,更多的資料大家可以查閱文件

開源實踐

恰巧前段時間做了個練手的yyblog的開源專案,這次就拿這個專案做個簡單的小程式客戶端了。還是慣例,大家先看下效果圖吧。

單純的html,css,js實現,沒有應用任何前端框架,還是比較適合參考學習的。ppps:反正我是不會說因為我不會才不用的 嗚嗚~~~流下了沒有技術的淚水┭┮﹏┭┮。

微信小程式總的來說雖然已經上線那麼久,但和傳統意義上的開發語言上比,還不是那麼穩定的,官方也在不斷的調整中。

相信很多同學有遇到過這樣的場景,當你第一次進入一個小程式的時候,會彈出來一個使用者資訊授權的彈窗。剛開始我寫的時候也是這樣處理的,但是後來在上傳程式碼的時候看到,微信在9月12號的時候發了一個公告。

主要是取消了分享監聽介面的回撥,將獲取使用者資訊的getUserInfo介面改為只有使用者點選了相關授權元件才能觸發,還有就是openSetting介面也改為了點選才能觸發。所以做微信小程式開發還是要做關注下官方的動態,以免做好的功能確不能正常使用的尷尬。

全域性配置

前面有說app.xx的相關檔案,是小程式的全域性配置檔案,這裡在單獨說下app.js這個檔案。當我們某些引數是全域性需要的時候,我們就可以將相關的引數寫在這個檔案裡面,比如我們請求的基礎url,亦或是使用者資訊,使用者ID這種請求必須攜帶的引數。同時我們可以將版本校驗的程式碼寫在這裡,這裡在多說一句,微信是支援版本校驗的,當有新的版本程式碼的時候,可以做使用者更新提示,這裡不再需要我們後臺校驗,還是比較方便的。相關的程式碼如下:

App({

  onLaunch() {
    this.checkUpdate();
  },

  globalData: {
    userInfo: {},
    apiBase: "https://www.laoyeye.net",
    userId: ""
  },

  checkUpdate() {
    const updateManager = wx.getUpdateManager();
    updateManager.onCheckForUpdate(function (res) {
      // 請求完新版本資訊的回撥
      console.log(res.hasUpdate)
    })
    updateManager.onUpdateReady(function () {
      wx.showModal({
        title: '更新提示',
        content: '新版本已經準備好,是否重啟應用?',
        success: function (res) {
          if (res.confirm) {
            // 新的版本已經下載好,呼叫 applyUpdate 應用新版本並重啟
            updateManager.applyUpdate()
          }
        }
      })
    })

    updateManager.onUpdateFailed(function () {
      // 新版本下載失敗
      console.log('更新失敗!')
    })
  }
})複製程式碼

啟動頁

使用者在剛開始進入小程式的時候,首先會展現一個啟動頁。起初我也不是這樣設計的,基本上是使用者進入後直接進入主頁,彈出使用者授權就行了,但是因為9.12的調整,也不得不作出了修改。讓使用者首先進入啟動頁授權,授權後跳轉到主頁。已授權的使用者就把授權按鈕隱藏,然後在等待1.5s後跳轉到主頁。這個過程中我除了做了獲取使用者授權的操作之外,還請求後臺伺服器在後臺建立了使用者資料,最終將userId返回到小程式。以後使用者做評論,點贊,收藏等操作,均會攜帶userId,方便區分具體的使用者。

這個頁面其實有兩個比較重要的知識要點,這裡特別強調下。

首先,我們需要獲取每個使用者對於當前應用的openId,以便下次使用者訪問時,避免再次授權的重複操作。

呼叫wx.login()介面獲取登入憑證(code)進而換取使用者登入態資訊,包括使用者的唯一標識(openid) 及本次登入的 會話金鑰(session_key)等。但是需要注意的是,用code去換取openid的操作,需要在服務端後臺來做,如果在小程式js上交換,在開發版本你會看到也是可以正常獲取登入,但是到生產上就不行了,因為小程式的安全限制,官方的域名是無法設定到白名單裡。

程式碼如下:

login(auth) {
    let that = this;
    //呼叫微信登入介面
    wx.login({
      success: function(res) {
        wx.request({
          url: app.globalData.apiBase + '/api/wx/login?code=' + res.code + '&nickname=' + app.globalData.userInfo.nickName +
            '&avatar=' + app.globalData.userInfo.avatarUrl,
          header: {
            'content-type': 'application/json'
          },
          success: function(res) {
            //userId
            if (res.data.code == 200) {
              app.globalData.userId = res.data.data;
              console.log('獲取使用者資訊=' + res.data.data);
              if (auth == 'auth') {
                that.direct();
              } else {
                let timer = setTimeout(() => {
                  clearTimeout(timer)
                  that.direct()
                }, 1500)
              }
            }
          }
        })
      }
    })
  },複製程式碼

第二,就是getUserInfo這個介面了,因為新規定的限制,以往如果使用者沒有授權,是會彈出授權的彈窗的。但是新規定之後如果你呼叫這個介面是在使用者沒有授權的情況下,那麼會直接進入fail失敗的回撥的。所以你必須通過元件獲取使用者的授權,然後在使用者點選的回撥裡在呼叫這個方法。

程式碼如下:

 <button class="show-btn" wx:if="{{userInfo.length == 0}}" type="primary" open-type="getUserInfo" bindgetuserinfo="onGetUserInfo"> 授權登入 </button>複製程式碼
onGetUserInfo() {
    var that = this;
    wx.getSetting({
      success: function(res) {
        if (res.authSetting['scope.userInfo']) {
          wx.getUserInfo({
            success: function(res) {
              app.globalData.userInfo = res.userInfo;
              that.login('auth');
            },
            fail: function() {
              console.log('系統錯誤')
            }
          })
        } else {
          wx.showToast({
            title: "授權失敗",
            duration: 1000,
            icon: "none"
          })
        }
      },
      fail: function() {
        console.log('獲取使用者資訊失敗');
      }
    })
  },複製程式碼

最後,這裡在講個小問題,我不知道是不是我個人的問題,我在做頁面資料賦值的時候,會使用

this.data.requestUrl = requestUrl;
或者
this.setData({
postList: totalData
});

的方法。如果是非同步情況下,必須使用方法二,頁面上才能取到資料。但是有些情況下非非同步方法裡使用方法一資料竟然取不出來,可是我在斷點中明明看到資料是賦值成功的啊。而這個時候換成方法二卻又成功了。真的是不明所以,大家儘量使用方法二吧。

主頁、技術頁

把這兩個頁面一起講,原因就是兩個頁面雖然展現形式上不同,但是技術特點上還是想同的。唯一的區別,可能就是後期我會把兩個頁面的資料介面做個調整,請求不同的資料了。

這個頁面主要是兩個知識點,上拉載入更多和下拉重新整理了。

首先是上滑載入更多資料,這個其實是小程式官方提供的一個onReachBottom的方法,只要使用者上滑到一定距離就會觸發,這裡我做了分頁的處理。首次進入展示五條資料,當觸發事件後請求第二頁的資料。當然請求到第二頁的資料並不能覆蓋之前的資料哦,不然當使用者在下滑時,剛才的資料沒了,是不符合使用者習慣的。

上滑事件觸發的距離也是可以通過onReachBottomDistance實現的,預設50px

具體實現的程式碼如下:

 // 上滑載入更多資料
  onReachBottom: function (event) {
    var nextUrl = this.data.requestUrl +
      "?page=" + this.data.page + "&limit=5";
    util.ajax(nextUrl, "get", null, this.processData)
    wx.showNavigationBarLoading()
  },複製程式碼
  processData: function (indexData) {
    var totalData = {};
    //如果要繫結新載入的資料,那麼需要同舊有的資料合併在一起
    if (!this.data.isEmpty) {
      totalData = this.data.postList.concat(indexData);
    }
    else {
      totalData = indexData;
      this.data.isEmpty = false;
    }
    this.setData({
      postList: totalData
    });

    this.data.page += 1;
    wx.hideNavigationBarLoading();
    wx.stopPullDownRefresh();
  },複製程式碼

然後是下拉重新整理,下拉重新整理預設是不開啟的,需要我們在*.json配置中通過enablePullDownRefresh屬性開啟,預設為false。

如果在app.json中設定為全域性開啟下拉重新整理,在具體頁面中即為當前頁面開啟。

相關程式碼如下:

{
  "navigationBarTitleText":"小賣鋪的老爺爺",
  "enablePullDownRefresh": true
}複製程式碼
  onPullDownRefresh: function (event) {
    var refreshUrl = this.data.requestUrl +
      "?page=0&limit=5";
    this.data.techList = {};
    this.data.isEmpty = true;
    this.data.page = 1;
    util.ajax(refreshUrl, "get", null, this.processData);
    wx.showNavigationBarLoading();
  },複製程式碼

其實這兩種方法,在大家看官方文件全域性配置的時候就會看到的。上面我也有說過學習小程式,官方文件的簡易教程和框架還是必看的,其他的就沒那麼重要了。

詳情頁

詳情頁其實就一個要講,富文字的解析。

因為微信小程式並不支援html語言,所以需要轉換為微信支援的wxml。

總的來說微信對富文字的支援並不好,官方也沒什麼好用的富文字解析元件。這次我使用的是github上關注度最高的小程式富文字元件wxParse ,雖說相對比較完善了,BUG還是不少的,而且作者好像也不維護了。但是目前實在沒有找到其他什麼好的替代方案,只能用這個了。如果大家還有其他元件,可以告訴我一下哈。

wxParse 的使用,專案上已經講的很清楚了,大家方便可以移步:https://github.com/icindy/wxParse 檢視。

我這邊對wxParse做了一些小改動,主要解決部分手機報錯無法解析的問題。原因是微信小程式不支援console.dir()的寫法,這個小程式官方也有在社群說明。

分享

當你在頁面的js檔案中,定義了onShareAppMessage函式,這時候頁面便擁有了分享功能,可以轉發給微信好友。

  /**
   * 使用者點選右上角分享
   */
  onShareAppMessage: function () {
    return {
      title: this.data.postData.title,
      path: '/pages/post-detail/post-detail?id=' + this.data.id + "&title=" + '小賣鋪的老爺爺' + "&share=1" 
    }
  },複製程式碼

如上,是我的分享程式碼,設定了分享的標題,以及跳轉的路徑等。這裡我對路徑做了引數處理,以便我能區分出使用者的來源。為什麼要區分使用者來源呢,因為小程式的分享頁面進入後有個很奇怪的問題,沒有返回主頁的按鈕。所以我這邊單獨做了區分,當使用者來自分享時,顯示一個懸浮的返回首頁的圖示。

相關程式碼如下:

<!-- 回到首頁(分享的時候顯示) -->
<image wx:if="{{share}}" bindtap='onBackHome' class='back-home' src='/images/icon/home-page.png' lazy-load></image>複製程式碼
  /**
  * 回到首頁(分享的時候)
  */
  onBackHome: function () {
    wx.reLaunch({
      url: '/pages/launch/launch?share=1"'
    })
  }複製程式碼

我的

最後在說說我的這個頁面,其實這個頁面沒啥重要的東西。只是靜態頁面的跳轉。

個人資訊後期我會做成可繫結PC端賬戶的形式。

我的收藏是已經實現過的,只是可能詳情頁還沒有具體收藏的入口,後期我會加上。具體的效果圖如下。

還有一個就是打賞讚助這個頁面,剛開始是準備做成小程式間關聯,使用給贊api的接入方式。但是最近小程式官方對多個小程式間的跳轉也要增加限制,就懶得弄了。

直接做了個詳情頁的跳轉,詳情頁面貼了張讚賞碼完事。需要注意的是小程式頁面並不支援直接長按掃描哦,需要點選下圖片,在彈出的圖片上在長按識別圖中的二維碼。

ppps:寫完文章後才想起來這個頁面忘記說一個東西。小程式是可以使用阿里icon庫的,具體使用方法大家網上看看吧。不說了,有興趣的也可以看下我原始碼中的實現。

最後的最後

附上小程式微信預覽地址:

之前有說這個專案是基於我前面的開源專案yyblog來寫的,所以專案的PC端是已經完成的。所有請求的介面均已在yyblog實現。

小程式的原始碼也已在yyblog中上傳,具體地址在:github.com/allanzhuo/y…

如果本文對您有幫助,或者專案能對您有所啟發的話,希望幫忙給yyblog專案點個Star吧,github.com/allanzhuo/y…

篇幅有限,寫得有點長了,就到這裡吧。總的來說技術難度不大,但是小坑還是比較多的。如果您有什麼想法歡迎在評論中與我交流,碼字不易,記得幫忙點個Star哦~


相關文章