微信小程序常见功能解决方案
(1)、异常监控
javascript
onError: function(msg) {
this.pushErrorToServer({
content:e,
category:t,
sec_category:n,
level:"error"
})
},
pushErrorToServer:function(errMsg){
//异常信息上传到服务器
wx.request(...)
}
(2)、request 请求并获取新 token 重新请求返回数据
javascript
/*
* request() 发送http请求
* method get,post,put,delete
* url 请求链接
* data 请求数据
* header 请求header
* return Promise
* example app.request('get', 'login', {}).then()
*/
request: function(method, api, data = {}) {
let that = this;
return new Promise((resolve, reject) => {
wx.showLoading({
title: '加载中...',
})
wx.request({
url: url + api,
data: data,
method: method,
success: function(r) {
wx.hideLoading();
// 请求资源成功
if (r.statusCode == 200) {
// 服务端返回数据状态判断
if (r.data.status == 200) {
// 数据获取成功
resolve(r.data)
} else if (r.data.status == 401) {
// 用户token过期
// 重新生成新的token
console.error('request-401' + r.data.msg);
that.againToken().then(ress => {
console.log('这里是新的token');
console.log(r.data);
// resolve(r.data);
// 重新请求接口
data.token = wx.getStorageSync('access_token');
that.request(method, api, data).then(thridRes => {
// 返回重新请求的数据
resolve(thridRes);
}, thridRes => {
reject(thridRes);
});
}, ress => {
console.log(ress)
});
} else if (r.data.status == 402) {
// 无效的token
// 重新生成新的token
console.error('request-402' + r.data.msg);
that.againToken().then(ress => {
// resolve(r.data);
// 重新请求接口
data.token = wx.getStorageSync('access_token');
that.request(method, api, data).then(thridRes => {
// 返回重新请求的数据
resolve(thridRes);
}, thridRes => {
reject(thridRes);
});
console.warn('无效token');
}, ress => {
console.log(ress)
});
} else if (r.data.status == 403) {
// 找不到用户信息,用户信息可能被删除
reject(r.data.msg);
} else if (r.data.status == 300) {
// 用户操作失败
reject(r.data.msg);
} else if (r.data.status == 500) {
// 缺少参数信息
reject(r.data.msg);
} else if (r.data.status == 501) {
// 非法的userid(openid)
reject(r.data.msg);
} else if (r.data.status == 502) {
// 非法的goodid
reject(r.data.msg);
} else {
// 未知状态码错误
reject(r.data.msg);
}
// 请求资源失败
} else if (r.statusCode === 404) {
reject('未找到页面(404)')
// 请求资源找不到或路径出错
} else if (r.statusCode === 500) {
reject('服务器错误(500)')
} else if (r.statusCode === 422) {
reject(r.data)
} else {
// 请求资源未知错误
reject('未知错误')
}
},
fail: function(r) {
wx.hideLoading();
// 请求接口调用失败
// 网络请求超时统一拦截
reject(r.errMsg || '出现错误(http fail)')
// console.log(r);
wx.showToast({
title: r.errMsg,
icon: 'none',
duration: 2000
})
}
})
})
},
// 获取新的token
againToken: function() {
let getOpenid = wx.getStorageSync('openID');
return new Promise((resolve, reject) => {
wx.request({
url: url + '/api/xxx',
method: 'POST',
data: {
openid: getOpenid
},
success: function(res) {
if (res.data.status == 200) {
console.log('获取新的token成功:' + res.data.data);
wx.setStorage({
key: "access_token",
data: res.data.data,
success: function(e) {
resolve();
},
fail: function(e) {
},
complete: function() {
// resolve();
}
})
} else {
console.error('其他错误!');
console.error(res);
reject(res);
}
},
fail: function(res) {
// 网络请求超时统一拦截
wx.showToast({
title: res.errMsg,
icon: 'none',
duration: 2000
})
reject(res);
}
})
})
},
(3)、定位授权重复判断
javascript
const that = this
wx.getLocation({
type: 'wgs84',
success(res) {
// 用户点击了授权
console.log(res)
latitude = res.latitude
longitude = res.longitude
// 获取我的参观记录
const data = {
page: that.data.page,
size: that.data.size,
lat: latitude,
lng: longitude,
token: wx.getStorageSync('access_token'),
}
app.request('POST', '/api/xxx', data).then((res) => {
console.dir(res)
that.setData({
tabInfos: res.data
})
}, (res) => {
console.error(res)
})
},
fail(res) {
console.log('用户取消的授权信息')
// 用户点击了取消选择地址信息
console.log(res)
// 当用户拒绝授权定位信息时调用
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
wx.getSetting({
success(res) {
if (!res.authSetting['scope.userLocation']) {
// 定位:用户没有授权
wx.openSetting({
success(res) {
console.log(res.authSetting)
// 用户已经同意小程序使用定位功能,后续调用 操作 接口不会弹窗询问
wx.getLocation({
type: 'wgs84',
success(res) {
// 用户点击了授权
console.log(res)
latitude = res.latitude
longitude = res.longitude
// 获取我的参观记录
const data = {
page: that.data.page,
size: that.data.size,
lat: latitude,
lng: longitude,
token: wx.getStorageSync('access_token'),
}
app.request('POST', '/api/xxx', data).then((res) => {
console.dir(res)
that.setData({
tabInfos: res.data
})
}, (res) => {
console.error(res)
})
},
fail(res) {
console.error(res)
}
})
},
fail(res) {
console.error(res)
}
})
}
}
})
}
})
(四)、下拉刷新
javascript
const that = this
console.log('触发底部刷新')
const localPage = that.data.page + 1 // 获取当期的起始获取索引值
wx.showLoading({
title: '加载中...',
})
const data = {
size: that.data.size,
page: localPage,
}
app.request('POST', '/api/xxx', data).then((res) => {
console.log(res)
wx.hideLoading()
// 判断获取后台内容是否为空
if (res.data == '' && res.data.length == 0) {
wx.showToast({
title: '亲~,已经全部加载完了',
icon: 'none',
duration: 2000
})
}
else {
// 设置页码为当前的页码+1
that.setData({
page: localPage
})
let addNextRes = Array
const addNext = that.data.commList
addNextRes = res.data
for (const item in addNextRes)
addNext.push(addNextRes[item])
that.setData({
commList: addNext
})
}
}, (res) => {
console.log(res)
})
(五)、小程序线上提示更新
javascript
// 线上版本发布后,迭代:让用户退出更新小程序为最新版本
const updateManager = wx.getUpdateManager()
wx.getUpdateManager().onUpdateReady(() => {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
}
})
})
(六)、常用注意事项及小问题
- 上传图片和预览图片后会刷新
onShow()==在用户是否选择图片后调用、onHide()用户点击删除图片操作事件就调用了
函数页面; toFixed()
不能解析字符串,要转换成parseInt()
、parseFloat()
;- 线上版本(手机调试)跟开发工具调试 token 不统一,经常报 token 无效或 openid 无效 =》取消掉不校验合法域名和清除缓存数据、最好也清除掉使用的小程序记录数据;
(七)、下载图片授权保存相册重复判断
javascript
// util.js下载接口:
// 保存二维码图片
function downloadActCodeImg(imgurl) {
wx.downloadFile({
url: imgurl,
success(res) {
// console.log("下载文件:success");
// console.log(res);
// 保存图片到系统相册
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success(res) {
// console.log("保存图片:success");
wx.showToast({
title: '保存二维码成功',
duration: 2000
})
},
fail(res) {
// console.log("保存图片:fail");
console.log(res)
}
})
},
fail(res) {
// console.log("下载文件:fail");
console.log(res)
}
})
}
// 点击判断事件:
if (!wx.saveImageToPhotosAlbum) {
wx.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
return
}
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.writePhotosAlbum" 这个 scope
wx.getSetting({
success(res) {
console.log('getSetting: success')
if (!res.authSetting['scope.writePhotosAlbum']) {
console.log('1-没有授权《保存图片》权限')
// 接口调用询问
wx.authorize({
scope: 'scope.writePhotosAlbum',
success() {
console.log('2-授权《保存图片》权限成功')
// 下载二维码图片
util.downloadActCodeImg('http://xxx.png')
},
fail() {
// 用户拒绝了授权
console.log('2-授权《保存图片》权限失败')
// 打开设置页面
wx.openSetting({
success(data) {
console.log('openSetting: success')
},
fail(data) {
console.log('openSetting: fail')
}
})
}
})
}
else {
console.log('1-已经授权《保存图片》权限')
// 下载二维码图片
util.downloadActCodeImg('http://xxx.png')
}
},
fail(res) {
console.log('getSetting: success')
console.log(res)
}
})
(八)、小程序坑:
- 安卓手机不支持
console.dir()
方法,会报错停止执行代码 ===》小程序使用console.dir()
;导致安卓程序停止,苹果无影响!,尽量不要使用console.dir()
;
(九)、动态设置标题:
javascript
wx.setNavigationBarTitle({
title: that.data.mername// 页面标题为路由参数
})
(十)、获取当前小程序路由
javascript
// 使用getCurrentPages可以获取当前加载中所有的页面对象的一个数组,数组最后一个就是当前页面。
const pages = getCurrentPages() // 获取加载的页面
const currentPage = pages[pages.length - 1] // 获取当前页面的对象
const url = currentPage.route // 当前页面url
(十一)、设置 textarea 换行并存储数据库
javascript
// &hc表示换行 用于输出时候的转换(存入数据库的时候转换)
var str = that.data.content.split('\n').join('&hc')
// 替换拿到的数据(获取到的数据库数据将数据替换回来)
var str = res.data.content.split('&hc').join('\n')
(十二)、获取指定类别选择器的容器属性(针对不同手机)
javascript
const that = this
const qSearch = wx.createSelectorQuery()
qSearch.select('.swiper-tab').boundingClientRect()
qSearch.exec((res) => {
console.log(`输出swiper-tab的高度${res[0].height}`)
that.setData({
useHeith: (Number.parseInt(that.data.useHeith) + Number.parseInt(res[0].height))
})
// timeAndTipsFixed高度
const qKillOrder = wx.createSelectorQuery()
qKillOrder.select('.timeAndTipsFixed').boundingClientRect()
const result = qKillOrder.exec((resk) => {
console.log(`输出timeAndTipsFixed的高度${resk[0].height}`)
that.setData({
useHeith: (Number.parseInt(that.data.useHeith) + Number.parseInt(resk[0].height))
})
// bannerType-view高度
wx.getSystemInfo({
success(resPhone) {
// console.log('输出手机屏幕的值:')
// console.dir(resPhone);
console.warn(`前两个节点高度和:${that.data.useHeith}`)
that.setData({
canUseWidth: resPhone.windowWidth,
canUseHeith: resPhone.windowHeight,
scrollViewHeith: (Number.parseInt(resPhone.windowHeight) - Number.parseInt(that.data.useHeith))
})
console.error(`屏幕高度${that.data.scrollViewHeith}`)
},
})
})
}) // 这一串都是为了设置scrollview高度
(十三) 多图上传格式
javascript
// 图片上传
uploadImgs: function (api, imgARR, keyName) {
return new Promise((resolve, reject) => {
let userImgARR = []; //定义一个数组来保存用户上传图片后返回的图片网络地址
for (let i = 0; i < imgARR.length; i++) {
wx.uploadFile({
url: url + api,
filePath: imgARR[i].path,
name: keyName,
formData: {
token: wx.getStorageSync('access_token')
},
success: function (res) {
let jsonARR = JSON.parse(res.data);
userImgARR.push(jsonARR.data.src);
if (i == imgARR.length - 1) {
resolve(userImgARR); //返回上传后的图片数组
}
},
fail: function (res) {
// 网络请求超时统一拦截
wx.showToast({
title: res.errMsg,
icon: 'none',
duration: 2000
})
}
})
}
})
},
(十五)、设置上一页的 setData 值
javascript
const pages = getCurrentPages() // 获取加载的页面( 页面栈 )
const currentPage = pages[pages.length - 1] // 获取当前页面
const prevPage = pages[pages.length - 2] // 获取上一个页面
// 设置上一个页面的数据(可以修改,也可以新增)
prevPage.setData({
back: true
})
// 返回上一个页面(这个API不允许跟参数)
wx.navgateBack({
delta: 1 // 表示返回到上一个页面(如果值为2表示回退到上上一个页面)
})
(十六)、获取当前页面的路径
console.log(获取当前页面的路径:${this.route}
);
(十七)、setData注意
setData
函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的this.data
的值(同步)。其中
key
可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如array[2].message,a.b.c.d,
并且不需要在this.data
中预先定义。
javascript
this.setData({
data: 'hello wrold'
}, () => {
// setData引起的界面更新渲染完毕后的回调函数
})
(十八)、小程序模块化
- 第一种写法
javascript
// common.js
function sayHello(name) {
console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {
console.log(`Goodbye ${name} !`)
}
module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye
- 第二种写法
javascript
module.exports = {
WxApiRoot: '123',
}
- 调用
javascript
const common = require('common.js')// 只能是相对路径
Page({
helloMINA() {
common.sayHello('MINA')
},
goodbyeMINA() {
common.sayGoodbye('MINA')
}
})
(二十)、checkbox 或 radio
<checkbox checked="false"></checkbox>
特别注意:不要直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值。
(二十一)、使用模板 template
可以同页面不同地方使用,也可以跨页面使用
- 定义一个模板页面
html
<template name='template_demo'>
<view>
<text>{{index}}: {{msg}}</text>
<text>Time: {{time}}</text>
</view>
</template>
- 别个页面引用
html
<import src="../templates/template.wxml"/>
<template is="template_demo" data="{{...item}}"></template>
(二十二)、使用动画
javascript
animation="{{updatePanelAnimationData}}"
javascript
/**
* 显示事项数据添加更新面板
*/
function showUpdatePanel() {
const animation = wx.createAnimation({
duration: 600
})
animation.translateY('-100%').step()
this.setData({
updatePanelAnimationData: animation.export()
})
}