不一樣的小程序開發

不一樣的小程序開發
關於微信小程序開發一直想寫一篇相關的文章總結和記錄下,結果拖延症犯了遲遲沒有下筆;這不最近天氣不錯,於是找一個空閒的下午將這篇文章輸出下(好像跟天氣沒啥關係)!

注意:本文默認開發者對微信小程序開發有一定語法基礎。

小程序小結

  在接觸的微信小程序開發過程中,不難發現微信小程序爲了方便開發人員入手對很多底層api進行了很好的封裝,比如針對接口請求的wx.request(),針對路由跳轉和頁面導航的wx.switchTab、wx.navigateTo···等。雖然在一定程度上簡化了開發,但是對於項目工程的系統化構建還是不夠的,因此本人在對比以前基於Vue開發項目的經驗和自身的開發習慣,總結出如下3點可供參考:

  • 1、全局變量和配置信息統一管理;

  • 2、封裝路由守衛相關api:vue-routerrouter.beforeEach()router.afterEach()真的香;
  • 3、接口請求公共信息進一步提取封裝;
  • 4、封裝接口的請求和響應攔截api:axiosaxios.interceptors.request.use()axios.interceptors.response.use()用過的都說好;

從上述四點出發,對微信小程序初始化工程進行規範優化,能夠很大程度提高開發效率和進行項目維護管理。封裝的好處不只體現在調用的方便上,也體現在管理的方便上,同時,公共操作集中處理,很大程度減少繁雜重複代碼。

一、項目初始化

   新建微信小程序項目,在項目下新建如下目錄和文件:

  • config文件夾:統一管理可配置的信息和變量;
    • erroList.js:接口報錯錯誤碼匹配列表文件;
    • globalData.js:全局變量統一管理文件(相當於vuex);
    • keys.js:可配置系統信息管理文件(全局常量命名等);
  • pages文件夾:小程序頁面文件管理文件夾(每個頁面一個子文件夾目錄);
  • router文件夾:路由管理文件件;
    • router.js:對微信小程序5種路由導航api的封裝;
    • routerConfig.js:頁面路由名稱和路徑匹配配置文件;
    • routerFilter.js:路由前置攔截封裝;
  • servers文件件:接口請求服務管理文件夾;
    • apis文件夾:request請求封裝管理和接口api配置管理文件夾;
    • request.js:對wx.requestPromise封裝;
    • xxx.js:對應模塊的接口管理文件;
    • requestFilter.js:接口請求和響應攔截封裝文件;
  • 其他都是初始化默認文件;

不一樣的小程序開發

二、路由跳轉和路由守衛封裝

1、路由跳轉封裝

  微信小程序官方文檔爲開發者提供了5種路由跳轉的api,每一種都有其特殊的用法:

不一樣的小程序開發

  根據其用法,我們對路由api進行如下封裝:微信小程序路由跳轉最後對應push、replace、pop、relaunch、switchTabroutes對應routeConfig.js中路由路徑的配置;routerFilter對應routerFilter.js文件,對路由跳轉之前的邏輯進行處理;

routeConfig.js(每次新增頁面後需要手動添加):

export const routes = 
  {
    INDEX: "/pages/index/index",
    TEST: "/pages/test/test",
  }
export default {...routes};

routerFilter.js:

export default () => {
  ···
  //路由跳轉前邏輯處理
}

router.js(routerFilter負責路由跳轉前公共操作處理,在success和fail中對路由跳轉後的公共操作進行處理):

import routes from "../router/routerConfig";
import routerFilter from "./routerFilter"

/**
 * 對wx.navigateTo的封裝
 * @param {路由} path 
 * @param {參數} params 
 * @param {事件} events 
 */
const push = (path, params, events) => {
  routerFilter()
  wx.navigateTo({
    url: routes[path] + `?query=${JSON.stringify(params)}`,
    events: events,
    success(res) {
      console.log(res);
    },
    fail(err) {
      console.log(err);
    }
  })
}

/**
 * 對wx.redirectTo的封裝
 * @param {路由} path 
 * @param {參數} params 
 */
const replace = (path, params) => {
  routerFilter()
  wx.redirectTo({
    url: routes[path] + `?query=${JSON.stringify(params)}`,
    success(res) {
      console.log(res);
    },
    fail(err) {
      console.log(err);
    }
  })

}

/**
 * 對wx.navigateBack的封裝
 * @param {返回的層級} number 
 */
const pop = (number) => {
  routerFilter()
  wx.navigateBack({
    delta: number,
    success(res) {
      console.log(res);
    },
    fail(err) {
      console.log(err);
    }
  })
}

/**
 * 對wx.reLaunch的封裝
 * @param {路由} path 
 * @param {參數} params 
 */
const relaunch = (path, params) => {
  routerFilter()
  wx.reLaunch({
    url: routes[path] + `?query=${JSON.stringify(params)}`,
    success(res) {
      console.log(res);
    },
    fail(err) {
      console.log(err);
    }
  })
}

/**
 * 對tabbar的封裝
 * @param {路由} path 
 */
const switchTab = (path) => {
  routerFilter()
  wx.switchTab({
    url: routes[path],
    success(res) {
      console.log(res);
    },
    fail(err) {
      console.log(err);
    }
  })
}

module.exports = {
  push,
  replace,
  pop,
  relaunch,
  switchTab
}

2、全局註冊和使用

app.js中對封裝的路由api進行全局註冊:

import router  from "./router/router.js"
//全局註冊
wx.router = router

在頁面邏輯中使用:

//index頁面跳轉test頁面 
gotoTest(){
   wx.router.push("TEST")
}

三、接口請求Promise封裝

  對於同一個項目而言,微信小程序apiwx.request()中很多參數都是相同的,如果直接使用,需要將這些重複參數一遍又一遍的copy,雖然copy很簡單,但是當有一個參數改變了需要找到所有接口一個一個修改,維護起來費勁,再者看着也難受呀;

不一樣的小程序開發

  借鑑axios對請求的封裝,將wx.request()封裝爲Promise形式豈不美哉:

request.js:

import formatError from "../requestFilter"
const app = getApp()

/**
 * 接口請求封裝
 * @param {請求方式} method 
 * @param {請求的url} url 
 * @param {請求傳遞的數據} data 
 */
const request = (method, url, data) => {
  //設置請求頭
  const header = {
    ···
  }
  //promise封裝一層,使得調用的時候直接用then和catch接收
  return new Promise((resolve, reject) => {
    wx.request({
      method: method,
      url: app.globalData.host + url, //完整的host
      data: data,
      header: header,
      success(res) {
        //對成功返回的請求進行數據管理和統一邏輯操作
        ···
        resolve(res.data)
      },
      fail(err) {
        wx.showToast({
          title: '網絡異常,稍後再試!',
          mask: true,
          icon: 'none',
          duration: 3000
        })
      }
    })
  })
}
export default request;

具體使用

以user.js爲例:

import request from "./request";

// 獲取用戶openid
export const usrInfos = data => request("POST", "/user/usrInfos", data);

index頁面調用:

//index.js
//獲取應用實例
const app = getApp()
import { usrInfos } from "../../servers/apis/user"

Page({
  onLoad: function () {
    //獲取用戶信息
    usrInfos({
      uid: "xxxx"
    })
      .then(res => {
        console.log(res)
      })
      .catch(err => {
        console.log(err)
      })
  }
})

四、接口的請求和響應攔截封裝

  axiosaxios.interceptors.request.use()axios.interceptors.response.use()分別對應接口請求前的攔截處理和數據響應後的攔截處理;根據這個原理我們對微信小程序的響應也做攔截封裝,對接口請求返回錯誤進行統一管理輸出:

request.js

import formatError from "../requestFilter"
const app = getApp()
···
const request = (method, url, data) => {
  ···
  return new Promise((resolve, reject) => {
    wx.request({
      ···
      success(res) {
        //對成功返回的請求進行數據管理和統一邏輯操作
        if(res.statusCode === 200){ //請求返回成功
          if(res.data && res.data.code === "SUCCESS"){ //後端對接口請求處理成功,返回數據給接口調用處
            resolve(res.data)  //then接收
          }else{        //後端對也請求判斷後認爲不合邏輯報錯
            formatError(res)   //統一的報錯處理邏輯
            reject(res.data)    //catch接收
          } 
        }else{
          reject(res.data)      //catch接收
        }
      },
      fail(err) {       //請求不通報錯
        wx.showToast({
          title: '網絡異常,稍後再試!',
          mask: true,
          icon: 'none',
          duration: 3000
        })
      }
    })
  })
}
export default request;

requestFilter.js

requestFilter.js中可以做很多對報錯的處理,這裏用一個簡單的toast處理示範下:

/**
 * 對接口返回的後端錯誤進行格式轉化
 * @param {接口成功返回的數據} res 
 */
const formatError = (err =>{
  wx.showToast({
    title: err.message,
    mask: false,
    icon: 'none',
    duration: 3000
  })
}

export default formatError;

對報錯進行統一處理需要明確數據規:

  • 制定統一的報錯碼管理規範;
  • 制定前後端統一的接口請求數據返回格式;

五、全局數據管理

  對於數據的管理在小項目的開發中顯得不那麼重要,但是隨着項目越來越大,數據越來越多,一個很好的數據管理方案能夠有效地避免很多bug,這也是vuex能夠在vue生態中佔有一席之地的原因。秉承着合理管理數據的原則,對於該封裝的數據堅決封裝,對於該分模塊管理的配置堅決分塊管理:

globalData.js

微信小程序中全局的數據管理放在app.jsglobalData屬性中,當數據太多或者app.js邏輯太複雜時,將全局數據提取出來單獨管理的確是個好方案:

export default {
  ···
  host: "http://www.wawow.xyz/api/test", //接口請求的域名和接口前綴 
  hasConfirm: "" //是否已經有了confirm實例
  currentPage: ""
  ···
}

keys.js

keys.js屬於個人開發中的習慣操作,將項目中可能用到的一些常量名稱在此集中管理起來,十分方便調用和修改維護:

export default {
  ···
  TOKEN: "token",
  STORAGEITEM: "test"
  ···
}

全局引用和註冊

引入app.js:

import router  from "./router/router.js"
import keys from "./config/keys"
import globalData from "./config/globalData"
//全局註冊
wx.router = router
wx.$KEYS = keys

//app.js
App({
  //監聽小程序初始化
  onLaunch(options) {
    //獲取小程序初始進入的頁面信息
    let launchInfos = wx.getLaunchOptionsSync()
    //將當前頁面路由存入全局的數據管理中
    this.globalData.currentPage = launchInfos.path
  },
  ···
  //全局數據存儲
  globalData: globalData
})

使用

在頁面代碼邏輯中可以通過app.globalData.hostwx.$KEYS.TOKEN方式進行調用;

六、總結

  上述關於微信小程序開發的幾個方面都是在實踐中學習和總結的,技術層面的實現其實很容易,但是個人覺得開發規範項目工程構建纔是一個項目的重要基礎;完善的規範能夠有效的提高開發效率和開發者之間非必要的扯皮!合理的項目工程構建能夠優化開發邏輯,提高代碼邏輯易讀性,減少後期項目的管理時間,同時給予項目更大的擴展性。

  歡迎大家討論留言、進行補充!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章