开发微信小程序近两个月的小白,简单记录一下记忆比较深刻的坑
一 固定定位fixed
scroll-view下不能通过fixed进行固定定位,无法到达页面底部,使用view即可。
二 canvas
业务中需要实现这样一个效果
vantWeapp 中有一个Circle 环形进度条的组件
大家需要注意的是size默认单位为px 而不是rpx 也就是说不可以自适应 需要通过 wx.getSystemInfoSync().windowWidth获取设备宽度后根据当前宽度得出一个系数实现自适应 另外canvas 标签默认宽度300px、高度150px。
三 lottie-miniprogram
这绝对是一个大坑,微信小程序对lottie的兼容性真的很差,真机调试情况下无法获取canvas,会报错,只能通过预览去看效果,这就给调试带来了困难。
但这只是开始,
需要注意的是在组件中获取canvas需要加上in(this) 要不然无法获取到canvas节点
本来以为这样就结束了,但现实很残酷,第一次进入页面渲染正常,但是再次进入页面,动画就不动了,然后去社区发现了很多类似的情况,应该是官方的bug,看到github上有人提出通过destory方法在退出页面时进行销毁就可以解决这个问题,但遗憾的是这个destory方法并未被官方采纳。于是又到处去搬砖(参考:https://developers.weixin.qq.com/community/develop/doc/000c6c7330ce30571a1a4537556c00?highLine=lottie)
略加修改后如下:
let frameFn = function () {};
let rid = 0;
let canvasDom = null;
wx.createSelectorQuery()
.select("#canvas")
.node((res) => {
const canvas = res.node;
const requestAnimationFrame = canvas.requestAnimationFrame;
canvas.requestAnimationFrame = function () {
console.log("句子评测中的动画");
frameFn = arguments[0];
rid = requestAnimationFrame.apply(canvas, arguments);
return rid;
};
// 页面第二次打开时动画默认不会开始,这里需要手动调用一次动画
canvas.requestAnimationFrame(frameFn);
canvasDom = canvas;
lottie.setup(canvas);
lottie.loadAnimation({
autoplay: true,
loop: true,
path: PUBLIC_RES + "data.json", //lottie json包的网络链接
rendererSettings: {
context: canvas._ctx,
},
});
})
.exec();
onUnload: function () {
canvasDom.cancelAnimationFrame(rid);
这样总能解决了吧,可是又出现了新的问题,小程序中有两个地方使用到了动画,单个页面多次进入渲染没有问题,但是如果A页面正常,切换到B页面,那B页面就又不动了,两个页面只有一个页面的动画正常,然后又去爬坑,这次,你猜怎么着,没爬出来果断放弃,一个页面仍然使用lottie-miniprogram,另一个页面直接用gif动画,嗯,真香
还有就是canvas不能直接用wx:if进行显示隐藏,获取不到节点会报错,可以考虑采用定位left:1000rpx实现
.canvas {
position: absolute;
bottom: 190rpx;
z-index: 100;
width: 226rpx;
height: 114rpx;
left: 10000rpx;
&.show {
left: 261rpx;
}
}
四 获取用户信息
获取用户昵称时,用到了wx.getUserInfo,但这个API需要用户授权,尝试用wx.authorize
拉取授权,但失败了,返回12007错误,好像这个API废弃了,必去通过button的开发能力拉取授权
<button wx:if="{{flag}}" class="login-btn" type="primary" open-type="getUserInfo" bindgetuserinfo="getUserInfo">
授权用户信息
</button>
五 关于云知声(语音评测API)
之前小程序保存用户录音用的是微信临时文件 tempFilePath,但只能保存三天,通过云知声url拼接的路径可以实现三个月的保存,但是需要获取header,尝试去监听第三方接口的请求头,但是没成功,后来发现可以直接在云知声返回的结果中拿到
export function hivoiceHttp({ recordPath, voiceData = {} }) {
wx.showLoading({
title: "评测中",
mask: true,
});
return new Promise((reslove, reject) => {
wx.uploadFile({
url: HIVOICE_BASEURL_HTTP,
header: {
"session-id": "uuid-t" + Date.now(),
appkey: "",
"score-coefficient": HIVOICE_LEVEL,
},
filePath: recordPath,
name: "voice",
formData: {
...voiceData,
},
// 在这可以拿到请求头
success(res) {
// 拿到header中的Session-Id并进行拼接
let headerArr = res.header["Session-Id"].split(":");
let myVoiceUrl = `https://edu.hivoice.cn/WebAudio-1.0-SNAPSHOT/audio/play/${headerArr[2]}/${headerArr[1]}/${headerArr[0]}`;
console.log(myVoiceUrl, "=三个月=");
wx.hideLoading();
let data = res.data || "{}";
// // console.log('uploadFile', data, voiceData)
if (res.statusCode === 200) {
if (typeof data === "string") {
data = JSON.parse(data);
}
// 音质检测
if (data.audioCheck) {
let flag = false;
const audioCheck = data.audioCheck;
}
data.myVoiceUrl = myVoiceUrl;
reslove(data);
} else {
// console.log('uploadFile-succ-statusCode', res.statusCode)
reject({ message: "非预期结果", res: data });
}
},
fail(err) {
wx.hideLoading();
reject(err);
},
});
});
}
六 引导层相关
坑一
灰色引导层采用固定定位,在ios下进行下拉刷新的时候,仍然置顶,但是在安卓下则会随着下拉刷新一起下来,找了一下,好像是官方的bug,需要手写一个下拉刷新的方法。
坑二
在做这个引导栏的时候,遮罩无法覆盖tabbar,有两种解决方案,一种是自己重写tabbar,但是可能兼容性不好,另一种也就是我才采用的方法,效果一般,仅供参考
我是先切一张tabbar的图片,在进入页面时先将tabbar隐藏,通过回调在隐藏结束后显示页面,同时显示定位到原来tabbar位置的切图,作为第二层,然后这时遮罩就可以进行覆盖了。
wx.hideTabBar({
success: () => {
this.setData({ firstLogoin: true, tabbarFlag: true });// firstLogoin为整个页面显示状态位,tabbarFlag为tabber状态位
},
});
七 SwipeCell 滑动单元格
这个组件直接引用后删除是没有样式的,需要手动添加一个样式
.van-swipe-cell__right {
display: inline-block;
width: 65px;
height: 44px;
font-size: 15px;
line-height: 44px;
color: #fff;
text-align: center;
background-color: #EC714F;
}
需求中要求一次只能进行一次删除,因而一条右滑删除打开,另一条右滑删除就需要自动闭合,这就需要open事件,但是重点是通过bind:open="onOpen"绑定,居然不触发,需要修改源码,通过triggerEvent进行触发
然后就可以触发了,如果不是当前打开的列表项,就通过selectComponent调用close()方法即可,代码已贴
<van-swipe-cell class="{{'van-swipe' + index}}" right-width="{{ 65 }}" wx:for="{{errorList}}" id="{{index}}" data-index="{{index}}" wx:key="{{index}}" async-close bind:open="onOpen" bind:close="onClose">
onOpen(event) {
const { position, name } = event.detail;
const { index } = event.currentTarget.dataset;
this.data.errorList.forEach((error, errorIndex) => {
if (errorIndex !== index)
this.selectComponent(".van-swipe" + errorIndex).close();
});
},
八 关于分享
想要让一个页面可以分享,调用onShareAppMessage就可以了,但是同一个页面通过不同页面跳转过来,需要根据跳转的来源判断是否可以进行分享,可以通过hideShareMenu来实现
if (...) {
wx.hideShareMenu({
menus: ["shareAppMessage", "shareTimeline"],
});
}
如果分享出去的页面需要调用接口进行页面的渲染,可以将登陆后置,放开当前接口的鉴权,涉及到鉴权的操作时再弹出登录提示即可。
九 IOS字体适配
诸如fish中i在ios下面i不显示.且会和f连在一起,所以需要更改字体为:
font-family: Helvetica Neue;
十 视频播放完返回按钮异常
视频播放完成后中间的暂停按钮层级高于左侧返回按钮,导致返回按钮失效,可以去掉中间的结束按钮
show-center-play-btn="{{false}}"
十一 音频播放
const back = wx.getBackgroundAudioManager()
播放背景音乐时,发现音频没有及时更新,加上时间戳后正常
back.src = `${src}?t=${Date.now()}`;
还需要注意的是 createInnerAudioContext 可以播放微信临时文件,getBackgroundAudioManager 不支持
十二 自定义微信小程序tabbar上边框的颜色
两个小程序项目均提到原生tabbar颜色较深的问题,但是
所以只能自己模拟
在app.less中,通过伪类添加tabbar上边框定位下去
page::after {
content: '';
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 2rpx;
background-color: #eeeeee;
z-index: 9999;
}
在app.json中将tabbar颜色设为白色
"tabBar": {
"borderStyle": "white",
},