強烈推介的(de)幾個(gè)微信小程序開發小技巧,簡單又實用 - 新聞資訊 - 雲南小程序開發|雲南軟件開發|雲南網站建設-昆明融晨信息技術有限公司

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不(bù)管是(shì)網站,軟件還是(shì)小程序,都要(yào / yāo)直接或間接能爲(wéi / wèi)您産生價值,我們在(zài)追求其視覺表現的(de)同時(shí),更側重于(yú)功能的(de)便捷,營銷的(de)便利,運營的(de)高效,讓網站成爲(wéi / wèi)營銷工具,讓軟件能切實提升企業内部管理水平和(hé / huò)效率。優秀的(de)程序爲(wéi / wèi)後期升級提供便捷的(de)支持!

您當前位置>首頁 » 新聞資訊 » 小程序相關 >

強烈推介的(de)幾個(gè)微信小程序開發小技巧,簡單又實用

發表時(shí)間:2021-1-6

發布人(rén):融晨科技

浏覽次數:56

前段時(shí)間在(zài)下開發了(le/liǎo)個(gè)微信小程序,開發過程中總結了(le/liǎo)一些我覺得對我有用的(de)小技巧,提煉出(chū)來(lái),相當于(yú)一個(gè)總結複盤,也(yě)希望可以(yǐ)幫助到(dào)大(dà)家。如果對大(dà)家确實有幫助,别忘了(le/liǎo)點贊哦 :star2: ~

1.03.2006090
v2.12.1

1. 開發中可能遇到(dào)的(de)坑以(yǐ)及 Tips

本來(lái)想寫個(gè)小技巧的(de),結果我總結了(le/liǎo)一堆坑,沒上(shàng)手之(zhī)前完全想象不(bù)到(dào)微信小程序的(de)開發體驗是(shì)如此之(zhī)差、如此之(zhī)爛,從微信開發者工具到(dào)所謂的(de)「全新語言」,都有一種濃濃的(de)半成品的(de) five 即視感,實在(zài)讓我 emmm.... 另外我發現網上(shàng)的(de)小程序文章大(dà)部分都是(shì)如何使用和(hé / huò)如何避坑的(de)實用文,而(ér)不(bù)是(shì)技巧文,這(zhè)也(yě)從側面反映了(le/liǎo)小程序的(de)坑多。

在(zài)微信小程序原生開發過程中,我不(bù)斷發出(chū)這(zhè)樣的(de)疑問「爲(wéi / wèi)什麽堂堂技術人(rén)才多如牛毛的(de)騰訊,會推出(chū)如此 laji」,很多弱智反人(rén)類的(de)地(dì / de)方,在(zài)兩三年前社區就(jiù)已經提出(chū)來(lái),官方回複已經反饋正在(zài)修複中,但幾年過去了(le/liǎo),還是(shì)沒有音信,官方回複仍然是(shì)一句冷冰冰的(de)「已反饋」 :triumph:

  1. 微信開發者工具經常熱更新不(bù)起作用甚至白屏,重新編譯也(yě)不(bù)行,隻能強行退出(chū)後再次打開;
  2. 跟上(shàng)一條類似,有時(shí)候一點樣式出(chū)錯,預覽整個(gè)都白屏,調試器裏也(yě)不(bù)說(shuō)哪裏的(de)問題,直接就(jiù)給你棄療不(bù)顯示,重新編譯也(yě)無法解決問題,隻能強行退出(chū)後再次打開;
  3. 跟上(shàng)一條類似,調試器裏報的(de)錯經常沒什麽用,驢頭不(bù)對馬嘴,讓人(rén)很難定位問題;
  4. Android 端自定義 Tabbar 在(zài)下拉刷新的(de)時(shí)候,也(yě)會跟着屏幕一起往下移,而(ér)且是(shì)無法繞過的(de) Bug,自定義 Tabbar 樣式都寫好了(le/liǎo)的(de)我又改成自帶的(de) Tabbar 了(le/liǎo)!
  5. import 的(de)路徑不(bù)支持絕對路徑,比如你希望引用 utils/fetch.js ,在(zài)不(bù)管多深的(de)組件裏面你都要(yào / yāo)慢慢 ../ 點到(dào)根目錄,同樣 .wxss 文件 @import 導入文件時(shí)也(yě)隻能使用相對路徑,所以(yǐ)就(jiù)會出(chū)現 ../../../../../../utils/fetch.js 這(zhè)種東西;
  6. 靜态資源路徑不(bù)能有漢字,有漢字就(jiù)無法加載;
  7. .wxs 文件不(bù)支持 ES6,隻能使用蹩腳的(de) ES5 寫法;
  8. .wxml 中隻能引入 .wxs 文件不(bù)能引入 .js 文件???
  9. 模闆 {{}} 中連方法都不(bù)能執行,隻能處理簡單的(de)運算如 + - * / ,如果遇到(dào)數據需要(yào / yāo) filter 的(de)場景,需要(yào / yāo)在(zài) .js 文件中預先格式化好再一個(gè)個(gè) setData ,比如經常寫的(de) [2,3,4].includes(type) ,居然都跑不(bù)起來(lái)!
  10. .wxs 文件中無法使用 Date 對象,所以(yǐ)不(bù)能 new Date() ,隻能使用蹩腳的(de) getDate 方法,正則也(yě)是(shì)一樣,生成正則對象需要(yào / yāo)使用 getRegExp 函數 getRegExp(pattern[, flags])
  11. .wxs 中可以(yǐ)調用其它 .wxs 文件,并且隻能 require 調用 .wxs 文件,引入的(de)文件必須使用相對路徑;
  12. setData 連一個(gè)對象合并都懶得做,如果 data: {a: {b: 1, c: 1}} ,那麽 setData({a: {b: 2}}) 就(jiù)會丢失 a.c 的(de)值,真是(shì)讓人(rén)火冒三丈啊,還要(yào / yāo) setData({['a.b': 2]}) 這(zhè)樣才行;
  13. IOS 上(shàng) Date 對象獲取任意時(shí)間參數比如 getDaygetTime 都爲(wéi / wèi) NaN,是(shì)因爲(wéi / wèi) IOS 的(de) Date 構造函數不(bù)支持 2018-04-26 這(zhè)種格式的(de)日期,必須轉換爲(wéi / wèi) 2018/04/26 這(zhè)種格式才會顯示正常;
  14. 開發版小程序有時(shí)候請求莫名其妙發不(bù)出(chū)去,右上(shàng)角三個(gè)點 enable debug 打開「開發調試」之(zhī)後就(jiù)莫名其妙能發出(chū)去請求了(le/liǎo),在(zài)多部手機上(shàng)都是(shì)這(zhè)樣,不(bù)明真相。

2. 微信請求 Promise 化

2.1 使用現成的(de)庫

安裝 Promise 庫 wx-promise-pro ,記得一定要(yào / yāo)帶 -s--production ,要(yào / yāo)不(bù)然無法構建成功。

npm i -S wx-promise-pro

然後在(zài) app.js 中:

import { promisifyAll } from 'wx-promise-pro'

promisifyAll()  // promisify all wx api

App({ ... })

之(zhī)後就(jiù)可以(yǐ)正常使用了(le/liǎo):

wx.pro.showLoading({
    title: '加載中',
    mask: true
})
  .then(() => console.log('in promise ~'))

2.2 自己實現

其實我們可以(yǐ)自己來(lái)實現一個(gè)這(zhè)樣的(de)庫,原理很簡單,以(yǐ)原生 API 的(de) wx.request 爲(wéi / wèi)例:

// 原生 API 使用方式
wx.request({
    url: '',     // 請求的(de) url
    data: {},    // 參數
    method: '',  // post、get
    success: res => {
        // 請求成功回調函數,res爲(wéi / wèi)回調參數
    },
    fail: res => {
        // 請求失敗回調函數,res爲(wéi / wèi)回調參數
    }
})

如果我們将其 Promise 化,應該的(de)調用方式希望是(shì):

// Promise 化後的(de)期望使用方式
wx.pro.request({
    url: '',     // 請求的(de) url
    data: {},    // 參數
    method: ''   // post、get
})
  .then(res => {
      // 請求成功回調函數,res爲(wéi / wèi)回調參數
  })
  .catch(res => {
      // 請求失敗回調函數,res爲(wéi / wèi)回調參數
  })

并且 then 函數返回的(de)是(shì)一個(gè) Promise 對象,讓這(zhè)個(gè)函數可以(yǐ)不(bù)斷鏈式調用下去,所以(yǐ)首先需要(yào / yāo) new 出(chū)來(lái)一個(gè) Promise 對象:

function request(opt) {
    return new Promise((resolve, reject) => {
        wx.request({
            ...opt,
            success: res => { resolve(res)},
            fail: res => {reject(res)}
        })
    })
}

這(zhè)裏代碼我們可以(yǐ)進一步改進,由于(yú) successfail 這(zhè)裏傳入的(de)參數隻是(shì)由 resolvereject 方法執行了(le/liǎo)下,所以(yǐ)可以(yǐ)直接傳入 resolvereject 方法即可。

另外,由于(yú)其他(tā)小程序原生 API 格式一緻,所以(yǐ)我們可以(yǐ)使用柯裏化方法,來(lái)将其他(tā)需要(yào / yāo)進行 Promise 化的(de) API 進行處理:

function promisify(api) {
    return (opt = {}) => {
        return new Promise((resolve, reject) => {
            api({
                ...opt,
                fail: reject,
                success: resolve
            })
        })
    }
}

然後,将柯裏化方法執行的(de)結果作爲(wéi / wèi)新的(de) Promise 化的(de) API 挂載到(dào) wx.pro 對象上(shàng):

// 将指定 API 進行 Promise 化
wx.pro.request = promisify(wx.request)

// 使用
wx.pro.request({...})
    .then(...)

然後爲(wéi / wèi)了(le/liǎo)方便我們使用其他(tā)方法,可以(yǐ)循環将 wx 對象上(shàng)可以(yǐ)被 Promise 化的(de)方法比如 requestscanCodeshowToastgetUserInfo 等一一挂載到(dào) wx.pro 對象上(shàng),使用時(shí)可以(yǐ)直接 wx.pro.xx ,由于(yú)這(zhè)個(gè)方法執行返回的(de)是(shì)一個(gè) Promise 對象,因此可以(yǐ)像其它 Promise 化的(de)對象那樣使用。

事實上(shàng),不(bù)知不(bù)覺,我們就(jiù)自己實現了(le/liǎo) wx-promise-pro 的(de)源碼,這(zhè)個(gè)庫的(de)核心代碼也(yě)就(jiù)是(shì)上(shàng)面那這(zhè)幾行

2.3 在(zài)項目中使用

有了(le/liǎo)上(shàng)面的(de)工具後,我們可以(yǐ)将其使用在(zài)項目中,爲(wéi / wèi)了(le/liǎo)不(bù)在(zài)項目中遍布 wx.requestwx.pro.request 這(zhè)裏可以(yǐ)簡單進行封裝,新建兩個(gè)文件如下:

// utils/api/fetch.js 封裝請求方法、請求攔截器

const app = getApp()

const BaseUrl = 'http://172.0.0.1:7300/mock'

const TokenWhiteList = [
    '/app/user/get-by-code'     // 不(bù)需要(yào / yāo)鑒權的(de)api手動添加到(dào)這(zhè)裏
]

/**
 * 設置請求攔截器
 * @param params 請求參數
 */
const fetch = (params = {}) => {
    // 攔截器邏輯
    if (!TokenWhiteList.includes(params.url)) {
        params.header = {
            'content-type': 'application/json',             // 默認值
            'token': app.globalData.token || ''
        }
    }

    if (params.url.startsWith('/')) {    // 拼接完整URL
        params.url = BaseUrl + params.url
    }

    // 返回promise
    return wx.pro.request({ ...params })
      .then(({ data: { code, message, data } }) => {
          // ... 各種異常情況的(de)邏輯處理
          // 與後端約定 code 20000 時(shí)正常返回
          if (code === 20000) return Promise.resolve(data)
          return Promise.reject(message)
      })
}

export { fetch }

然後再将所有 API 封裝到(dào)單獨的(de)文件中集中管理:

// utils/api/apis.js 封裝所有請求 API

import { fetch } from './fetch'

/* 根據微信code獲取用戶信息 */
const appUserGetByCode = ({ code } = {}) => fetch({
    url: '/app/user/get-by-code',
    data: { code }
})

/* 掃碼登錄 */
const appUserQrLogin = ({ qrCode } = {}) => fetch({
    method: 'POST',
    url: '/app/user/qr-login',
    data: { qrCode }
})

/* 個(gè)人(rén)信息 */
const appUserInfo = () => fetch({
    url: '/app/user/info'
})

/* 系統參數獲取,數據字典 */
const appSysParamListByParam = () => fetch({
    url: '/app/sys-param/list-by-param'
})

/* 數據字典所有 */
const appSysParamListAll = () => fetch({
    url: '/app/sys-param/list-all'
})

export {
    appSysParamListAll,   // 數據字典所有
    appSysParamListByParam,   // 系統參數獲取,數據字典
    appUserGetByCode,   // 根據微信code獲取用戶信息
    appUserQrLogin,   // 掃碼登錄
    appUserInfo   // 個(gè)人(rén)信息
}

在(zài)要(yào / yāo)使用 API 的(de)地(dì / de)方就(jiù)可以(yǐ)這(zhè)樣引入:

import * as Api from '../../utils/api/apis.js'   // 相對路徑

// 使用方式
Api.appSysParamListAll()
  .then(({ dataList }) => this.upData({ sysParamList: dataList }))
  .then(() => {
      const keyList = this.data.sysParamList.map(T => T.key)
      this.upData({
          keyList,
          formData: { keys: keyList }
      })
  })

使用方式就(jiù)很舒服,這(zhè)裏使用到(dào)了(le/liǎo) upData,就(jiù)是(shì)下面我要(yào / yāo)介紹的(de)内容,是(shì)在(zài)下非常推介的(de)小程序工具~

3. setState 修改 data 中想修改對象的(de)屬性

在(zài)小程序中, data 是(shì)不(bù)能直接操作的(de),需要(yào / yāo)使用 setData 函數。鑒于(yú)微信小程序開發時(shí) setData 的(de)使用體驗十分蹩腳,我使用了(le/liǎo)個(gè)庫函數 wx-updata ,這(zhè)個(gè)庫函數在(zài)開發的(de)時(shí)候對我很有幫助,這(zhè)裏特意推介給大(dà)家。

3.1 爲(wéi / wèi)什麽要(yào / yāo)使用 wx-updata

你在(zài)使用 setData 的(de)時(shí)候,是(shì)不(bù)是(shì)有時(shí)候覺得很難受,舉個(gè)簡單的(de)例子(zǐ):

// 你的(de) data
data: {
    name: '蠟筆小新',
    info: { height: 140, color: '黃色' }
}

如果要(yào / yāo)修改 info.height 爲(wéi / wèi) 155,使用 setData 要(yào / yāo)怎麽做呢:

// 這(zhè)樣會把 info 裏其他(tā)屬性整不(bù)見了(le/liǎo)
this.setData({ info: { height: 155 } })

// 你需要(yào / yāo)取出(chū) info 對象,修改後整個(gè) setData
const { info } = this.data
info.height = 155
this.setData({ info })

似乎并不(bù)太複雜,但如果 data 是(shì)個(gè)很大(dà)的(de)對象,要(yào / yāo)把比較深且不(bù)同的(de)對象、數組項挨個(gè)改變:

data: {
    name: '蠟筆小新',
    info: {
        height: 140, color: '黃色',
        desc: [{ age: 8 }, '最喜歡大(dà)象之(zhī)歌', '靓仔', { dog: '小白', color: '白色' }]
    }
}

比如某個(gè)需求,需要(yào / yāo)把 info.height 改爲(wéi / wèi) 155,同時(shí)改變 info.desc 數組的(de)第 0 項的(de) age 爲(wéi / wèi) 12,第 3 項的(de) color 爲(wéi / wèi)灰色呢?

// 先取出(chū)要(yào / yāo)改變的(de)對象,改變數字後 setData 回去
const { info } = this.data
info.height = 155
info.desc[0].age = 12
info.desc[3].color = '灰色'
this.setData({ info })

// 或者像某些文章裏介紹的(de),這(zhè)樣可讀性差,也(yě)不(bù)太實用
this.setData({
    'info.height': 155,
    'info.desc[0].age': 12,
    'info.desc[3].color': '灰色'
})

上(shàng)面這(zhè)兩種方法,是(shì)我們平常小程序裏經常用的(de),和(hé / huò)其他(tā) Web 端的(de)框架相比,就(jiù)很蹩腳,一種濃濃的(de)半成品感撲面而(ér)來(lái),有沒有這(zhè)樣一個(gè)方法:

this.upData({
    info: {
        height: 155,
        desc: [{ age: 12 }, , , { color: '灰色' }]
    }
})

這(zhè)個(gè)方法會幫我們深度改變嵌套對象裏對應的(de)屬性值,跳過數組項裏不(bù)想改變的(de),隻設置我們提供了(le/liǎo)的(de)屬性值、數組項,豈不(bù)是(shì)省略了(le/liǎo)一大(dà)堆蹩腳的(de)代碼,而(ér)且可讀性也(yě)極佳呢。

這(zhè)就(jiù)是(shì)爲(wéi / wèi)什麽我在(zài)上(shàng)線的(de)項目中使用 wx-updata ,而(ér)不(bù)是(shì) setData

wx-updata 的(de)原理其實很簡單,舉個(gè)例子(zǐ):

this.upData({
    info: {
        height: 155,
        desc: [{ age: 12 }]
    }
})

// 會被自動轉化爲(wéi / wèi)下面這(zhè)種格式,
// this.setData({
//    'info.height': 155,
//    'info.desc[0].age': 12,
// })

原來(lái)這(zhè)個(gè)轉化工作是(shì)要(yào / yāo)我們自己手動來(lái)做,現在(zài) wx-updata 幫我們做了(le/liǎo),豈不(bù)美哉!

3.2 wx-updata 使用方式

在(zài)一般情況下,我們可以(yǐ)将方法直接挂載到(dào) Page 構造函數上(shàng),這(zhè)樣就(jiù)可以(yǐ)在(zài) Page 實例中像使用 setData 一樣使用 upData 了(le/liǎo):

// app.js 中挂載
import { updataInit } from './miniprogram_npm/wx-updata/index'  // 你的(de)庫文件路徑

App({
    onLaunch() {
        Page = updataInit(Page, { debug: true })
    }
})

// 頁面代碼中使用方式
this.upData({
    info: { height: 155 },
    desc: [{ age: 13 }, '帥哥'],
    family: [, , [, , , { color: '灰色' }]]
})

有的(de)框架可能在(zài) Page 對象上(shàng)進行了(le/liǎo)進一步修改,直接替換 Page 的(de)方式可能就(jiù)不(bù)太好了(le/liǎo), wx-updata 同樣暴露了(le/liǎo)工具方法,用戶可以(yǐ)在(zài)頁面代碼中直接使用工具方法進行處理:

// 頁面代碼中
import { objToPath } from './miniprogram_npm/wx-updata/index'  // 你的(de)庫文件路徑

Page({
    data: { a: { b: 2}, c: [3,4,5]},

    // 自己封裝一下
    upData(data) {
        return this.setData(objToPath(data))
    },

    // 你的(de)方法中或生命周期函數
    yourMethod() {
        this.upData({ a: { b: 7}, c: [8,,9]})
    }
})

針對修改數組指定項的(de)時(shí)候,可能存在(zài)的(de)跳過數組空位的(de)情況,wx-updata 提供了(le/liǎo) Empty 的(de) Symbol 類型替位符,還有數組的(de)對象路徑方式,感興趣可以(yǐ)看看 wx-updata 的(de) 文檔 。

另外,使用了(le/liǎo) wx-updata 也(yě)還可以(yǐ)使用原來(lái)的(de) setData,特别是(shì)有時(shí)候要(yào / yāo)清空數組時(shí),靈活使用,可以(yǐ)獲得更好的(de)小程序開發體驗,祝大(dà)家小程序開發愉快

4. 使用 scss 寫樣式

4.1 Webstorm 配置方法

關于(yú)蹩腳的(de) .wxss 樣式,我使用 webstorm 的(de) file watcher 工具把 scss 文件監聽改動并實時(shí)編譯成 .wxss 文件,感覺比較好用,這(zhè)裏給大(dà)家分享一下我的(de)配置:

然後記得在(zài) .gitignore 文件中加入要(yào / yāo)忽略的(de)樣式:

*.scss
*.wxss.map

這(zhè)樣在(zài)上(shàng)傳到(dào) git 的(de)時(shí)候,就(jiù)不(bù)會上(shàng)傳 scss 文件了(le/liǎo)~ 當然如果你的(de)團隊成員需要(yào / yāo) scss 的(de)話,還是(shì)建議 git 上(shàng)傳的(de)時(shí)候也(yě)加上(shàng) scss 文件。

這(zhè)樣設置之(zhī)後,一個(gè)組件在(zài)本地(dì / de)的(de)會是(shì)下面這(zhè)樣

其中我們需要(yào / yāo)關注的(de)就(jiù)是(shì) .js.json.scss.wxml 文件,另外的(de)文件 .wxss 會在(zài)你改動 .scss 文件之(zhī)後自動生成并更新,而(ér) .wxss.map 是(shì)插件自動生成的(de)映射關系,不(bù)用管。

如果不(bù)是(shì)使用 webstorm,可以(yǐ)直接執行命令 sass --watch index.scss:index.wxss -s expanded ,命令行如果關閉,sass 命令就(jiù)不(bù)會監聽文件的(de)變動然後編譯,所以(yǐ)最好用編輯器的(de)插件。

同理,也(yě)可以(yǐ)使用 less、stylus 等預編譯語言。

4.2 Visual Studio Code 配置方法

萬能的(de) VSC 當然也(yě)可以(yǐ)做到(dào)這(zhè)個(gè)功能,搜索并下載插件 easy sass ,然後在(zài) setting.json 中修改/增加配置:

"easysass.formats": [
  {
    "format": "expanded",
    "extension": ".wxss"
  },
  {
    "format": "compressed",
    "extension": ".min.wxss"
  }
]

上(shàng)面 expanded 是(shì)編譯生成的(de) .wxss 文件,下面 compressed 是(shì)壓縮之(zhī)後的(de) .wxss 樣式文件,下面這(zhè)個(gè)用不(bù)到(dào)可以(yǐ)把下面這(zhè)個(gè)配置去掉,然後在(zài) .gitignore 文件中加入要(yào / yāo)忽略的(de)中間樣式:

*.scss

當然也(yě)可以(yǐ)不(bù)添加,如果你的(de)同事也(yě)是(shì)實用 scss 來(lái)開發小程序的(de)話,其他(tā)跟上(shàng)面一樣,至此你就(jiù)可以(yǐ)在(zài)小程序開發中快樂使用 scss 了(le/liǎo)~

5. 使用 iconfont 圖标字體

在(zài) Web 開發中 iconfont 可謂是(shì)最常用的(de)靈活圖标字體工具了(le/liǎo),這(zhè)裏介紹一下如何在(zài)微信小程序中引入 iconfont 圖标。

首先找到(dào)你想使用的(de)圖标們,點擊購物車之(zhī)後下載到(dào)本地(dì / de)。

下載到(dào)本地(dì / de)是(shì)一個(gè)壓縮包,解壓縮之(zhī)後将 iconfont.css 文件複制到(dào)微信小程序的(de) styles 文件夾中 (在(zài)下的(de)習慣,也(yě)可以(yǐ)放到(dào)你想放的(de)地(dì / de)方比如 fonts ),将後綴改爲(wéi / wèi) .wxss

在(zài) app.wxss 中引入樣式:

@import "styles/iconfont.wxss";

然後在(zài) .wxml 中就(jiù)可以(yǐ)使用剛剛你添加的(de)圖标了(le/liǎo),Web 使用 i 标簽,小程序中使用 text 标簽:

<text class="iconfont icon-my-edit" style="color: blue"></text>

如果後面要(yào / yāo)加新的(de)圖标,要(yào / yāo)下載新的(de) iconfont.css 的(de)文件到(dào)本地(dì / de)重命名并覆蓋,重新走一遍這(zhè)個(gè)流程。

當然,如果你使用的(de)樣式庫提供的(de)一些 icon 能滿足你的(de)要(yào / yāo)求,那更好,就(jiù)不(bù)用引入外部圖标字體文件了(le/liǎo),不(bù)過大(dà)部分情況下是(shì)不(bù)滿足的(de)


相關案例查看更多