微信小程序官方提供的API很多用起来都有点鸡肋,针对不同项目的业务需求做二次封装是有必要的,这篇文章记一些有通用性的封装,若读者觉得有不好的地方,欢迎指出。
ChangeLog
- 2019-03-19 更新异步aip转为Promise风格、消息提示、页面信息传递
1. 异步api转为Promise风格
小程序中的异步api,风格都是统一为成功接受success参数作为回调,失败接受fail作为参数回调。比起Promise风格来说,感觉后者对开发者来说更加友好。
异步api转为Promise风格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
export const promisifyWxApi = fn => { return args => { return new Promise((resolve, reject) => { fn({ ...args, success: res => resolve(res), fail: res => reject(res), }) }) } }
|
1.1 使用举例
1 2 3 4 5 6 7
| promisifyWxApi(wx.chooseImage)({ count: 1, }).then(res => { console.log(res.tempFilePaths.pop()) }, () => { console.error('选择图片失败') })
|
2. 路由跳转
官方提供了四种页面跳转的方式,接受参数类型是一个Json,使用起来复杂又麻烦。
建议合并四种方式,简化参数形式。
路由跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const TABBAR_PAGES = ['productList', 'me']
const navigateTo = (pageName, urlParams, close) => { const objParams = {} let isTabbarPage = TABBAR_PAGES.indexOf(pageName) !== -1 let strParams = '' for (const key in urlParams) { if (!urlParams.hasOwnProperty(key)) { continue } strParams += `${key}=${encodeURIComponent(urlParams[key])}&` } strParams = strParams.replace(/&$/, '')
objParams.url = `/pages/${pageName}/${pageName}${strParams ? `?${strParams}` : ''}`
if (close === 'all' || (isTabbarPage && close)) { wx.reLaunch(objParams) } else if (isTabbarPage) { wx.switchTab(objParams) } else if (close) { wx.redirectTo(objParams) } else { wx.navigateTo(objParams) } }
|
2.1 使用举例
假设productList是一个tabbar页面,detail是一个普通页面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| wxUtil.navigateTo('productList')
wxUtil.navigateTo('productList', '', true)
wxUtil.navigateTo('productList', '', 'all')
wxUtil.navigateTo('detail', { productId: 'sq12345' })
wxUtil.navigateTo('detail', { productId: 'sq12345' }, true)
|
2.2 特殊说明
- 需要手动配置tabbar页面列表。
- 方法会对参数做编码,所以如果参数值包含中文,取用时要解码。
- tabbar页面只能通过reLaunch实现关闭当前页。
3. 刷新当前页
如果程序缓存的token失效,或者遇到某些异常时,需要重新刷新加载页面。
此方法是对方法1的扩展。
1 2 3 4 5
| function refresh () { const page = getCurrentPages().pop() const route = (page.route.split('/'))[2] navigateTo(route, page.options, true) }
|
4. 消息提示
官方提供了 showToast 和 showLoading 两个消息提示的API,使用频率很高,Json的参数类型就显得很麻烦了。
Toast提示重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
const showToast = (title = '', icon = 'warning', others) => { const params = { title, icon, mask: true, duration: 3000, ...others, } if (icon === 'warning') { params.image = '../../images/warning-o.png' } return promisifyWxApi(wx.showToast)(params) }
|
4.1 使用举例
1 2 3 4 5 6
| wxUtil.showToast('加载中...', 'loading', { ducation: 2000 })
wxUtil.showToast('操作成功', 'success')
wxUtil.showToast('手机号必填')
|
5. 发起网络请求
实际业务中需要对全部或绝大部分网络请求做统一的错误处理和数据预处理。
request重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| const headers = { 'content-type': 'application/x-www-form-urlencoded' }
function ajax (params, success, error) { const config = getApp().config const curTime = (new Date().getTime()) / 1000 if (config.APP_TOKEN && curTime >= config.TIME_EXPIRE) { showToast('登录失效,正在刷新页面') delete config.APP_TOKEN setTimeout(() => { refresh() }, 1000) return } wx.request({ method: 'POST', dataType: 'json', header: headers, success (res) { if (!res || res.statusCode !== 200 || !res.data) { error && error() return } if (!res.data.errno) { success && success(res.data.data) return } error && error(res.data.errno, res.data.msg) }, fail () { error && error() }, ...params }) }
|
5.1 使用举例
假设接口返回的内容格式为:
1 2 3 4 5
| { "errno": "xxx", "msg": "xxx", "data": "xxx" }
|
1 2 3 4 5 6 7 8 9 10 11
| wxUtil.ajax({ url: 'xxx', data: { key: 'xxx' } }, (res) => { }, (errno, msg) => { })
|
5.2 特殊说明
- 在实际项目中,方法应该根据接口的Header信息、出参格式稍作调整。
6. 图片预览
官方提供的图片预览API,接受的参数同样是Json类型,回调方法一般使用不到。可以二次封装做一些简化。
预览图片重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
function previewImage (index, urls) { if (!Array.isArray(urls) || index < 0 || index > urls.length - 1) { return } wx.previewImage({ current: urls[index], urls: urls }) }
|
6.1 使用举例
1 2 3 4 5 6 7 8 9 10
| Page({ data: { imgList: ['1.jpg', '2.jpg', '3.jpg'] }, bindPreviewImg (e) { const self = this const index = e.currentTarget.dataset.index wxUtil.previewImage(index, self.data.imgList) } })
|
7. 页面信息传递
很多业务场景都需要在页面间传递状态,传递方式要满足使用简单,状态值易于管理的要求。
页面信息传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| const NOTICE = { edit: Symbol('edit') } APP({
setNotice(key, value) { const noticeKey = NOTICE[key] if (!noticeKey) { return } if (value === undefined) { delete this.global[noticeKey] return } this.setConfig({ [noticeKey]: value }) },
getNotice(key) { const noticeKey = NOTICE[key] if (!noticeKey) { return '' } return this.global[noticeKey] },
checkNotice(key, value, callback) { if (this.getNotice(key) === value) { this.setNotice(key) typeof callback === 'function' && callback() } }, })
|
7.1 使用举例
场景:希望在编辑页提交数据之后,回到详情页,通知详情页刷新页面数据。
1 2 3 4 5 6 7
| const APP = getApp() Page({ submit () { APP.setNotice('edit', true) } })
|
1 2 3 4 5 6 7 8 9
| const APP = getApp() Page({ onShow () { APP.checkNotice('edit', true, () => { console.log('Page edit has been changed') }) } })
|
7.2 特殊说明
- setNotice (key, value)
- 设置全局的消息变量
- 若value值缺省,则会删除对应键值
- getNotice (key)
- checkNotice (key, value, callback)
- 检查键值对应消息值,符合条件则callback并删除对应键值
- 3个方法为了全局内可调用,写在app.js里。
- key应该放在变量NOTICE中统一管理,借助Symbol做唯一性处理。