微信小程序开发常见问题

摘要

微信小程序的出现方便了用户,却将小程序的开发者推向了“无尽的深渊”。

API的不断变更以及随处可能出现的未知bug,稍不留神你就掉坑里了,想要爬出来,我们只能使出浑身解数来“填坑”。这里需要重点“表扬”一下TX:见过坑人的,没见过像TX这么坑人的。

微信小程序的出现方便了用户,却将小程序的开发者推向了“无尽的深渊”。

API的不断变更以及随处可能出现的未知bug,稍不留神你就掉坑里了,想要爬出来,我们只能使出浑身解数来“填坑”。这里需要重点“表扬”一下TX:见过坑人的,没见过像TX这么坑人的。

古语有云:前人栽树,后人乘凉。今天,笔者就把自己在微信小程序开发过程中遇到的问题分享给大家。重要说明:笔者开发小程序是借助第三方开源项目mpvue,所以有些解决方案自然也是基于mpvue实现的,下面不再赘述。

替换npm为淘宝镜像(如无必要,尽量不要使用镜像)

---->卸载cnpm命令(npm uninstall cnpm -g),此条只针对全局安装过cnpm的人

注:打开DOS面板,执行npm config set registry https://registry.npm.taobao.org

如果想恢复默认,打开DOS面板,执行npm config set registry https://registry.npmjs.org

特别说明:替换npm为淘宝镜像原因是因为npm在国内访问不太稳定。当然,如果你的网络访问npm没问题,可忽略这步;

特别强调:淘宝镜像和cnpm是不一样的,这里设置的是淘宝镜像而不是cnpm。经过笔者多次踩坑和血淋淋的教训得出的结论——珍爱生命,远离cnpm

1、mpvue项目依赖安装失败

笔者发现,随着mpvue版本的迭代,不知从哪个版本开始,npm版本过低会导致依赖安装失败。知道了原因后,我们就可以“对症下药”了。解决方案如下:

1、升级Node.js客户端版本

2、升级npm版本

  1. npm install npm -g

注:以上方法任选一种即可。如果感觉自己Node版本过低,推荐使用第一种方案。

2、小程序组件有些默认样式无法覆盖

小程序提供的组件大多数都有默认值。很多时候我们需要进行重写,但是在开发工具中会发现无法覆盖其默认样式。经测试,基本上所有组件的默认样式的优先级都会高于标签选择器设置的样式,而class和id选择器的优先级还是高于默认样式,但class也是有个别例外情况的。

解决方案:优先使用class来覆盖默认样式,如果还不行,在使用id来覆盖默认样式。

3、图片上传页面数据丢失

原因:微信小程序上传图片成功之后会自动刷新页面(这个叫法可能并不恰当,因为笔者并没有看到页面刷新,但是确实重新走了一遍onShow钩子函数)。

解决方案:使用vue提供的mounted钩子函数代替小程序的onShow钩子函数

4、页面数据无法及时销毁

当我们从一个列表进入到详情页,在后退回列表页,然后在进入另一个详情页,我们会发现上新数据显示之前会先显示上一次的数据。

解决方案:在小程序的onUnload钩子函数中手动进行一次初始化赋值,代码如下:

  1. onUnload() {
  2.   Object.assign(this.$data, this.$options.data());
  3. }

5、页面路由跳转不执行

小程序的页面跳转分为两类,一类是tabBar页面之间的跳转,一类是页面直接的跳转。很多时候我们往往是通过方法进行页面之间的跳转。这是如果我们没搞清我们跳转的是哪类页面,则会出现页面路由跳转不执行的情况。

解决方案:跳转tabBar页面请使用switchTab,跳转非tabBar页面请使用navigateTo,redirectTo,如果不确定是哪类页面,建议一律使用reLaunch。

6、圆角失效问题

很多时候,设计师提供给我们的效果图中都会用到圆角。

圆角效果对于CSS3来说,犹如探囊取物一般(前提是不考虑浏览器的兼容性问题)。我们不要高兴的太早,因为今天我们要说的是小程序圆角问题。如此一个简单的属性,在小程序中却会出现问题。笔者就遇到过类似的问题,去官方社区一搜关键词,类似问题铺天盖地席卷而来。对于这种“烂大街”的问题,官方似乎迟迟不愿从根本上解决这个问题。

常言道:办法总比困难多。但是到了小程序这里就行不通了。此时,你是否也和笔者一样,脑中会浮现一个“散发着迷般微笑的人物,上书‘这个问题,充钱可以解决’”的表情包。

言归正传,圆角失效问题可以归为两类。

1、官方组件本身bug

对于官方提供的组件,有些确实是官方组件的bug,这一类开发者是无能为力的,只能“等待”官方修复。

2、写法不当(官方为开发者挖的坑),举例说明:

<open-data class="avatar" type="userAvatarUrl"></open-data>

这个是官方提供的组件,目前官方并没有提供圆角参数,所以想要实现圆角效果,我们往往要自己动手了。比如我们要个80X80像素的圆角头像,定势思维我们会这样写:

  1. .avatar {
  2.   width80px;
  3.   height80px;
  4.   border-radius: 50%;
  5. }

对于这种写法,如果外面没有其他样式影响的情况下,是无法达到我们需要的效果。所以我们应该改写为如下:

  1. .avatar {
  2.   displayblock;
  3.   width80px;
  4.   height80px;
  5.   border-radius: 50%;
  6.   overflowhidden;
  7. }

注:排除上面两种情况,如果我们发现使用圆角之后存在诡异bug,我们可以尝试给添加了圆角的元素添加will-change: transform;属性,或许会有意料不到的结果,不过好像这个属性会影响性能,具体权衡在你。

7、小程序蓝牙问题

小程序对于蓝牙的处理,可以说是到处是坑。遇到问题,解决bug的过程可以让你怀疑人生。为了避免更多的人被坑,笔者把自己遇到的问题和解决方案分享出来。

特别提醒:小程序中的deviceId,characteristicId,serviceId尤为重要,缺一不可;如果你要兼容安卓手机和苹果手机,请按下面步骤书写,可根据自己需要做适当变更

1、初始化蓝牙适配器

  1. let [deviceId, characteristicId, characteristicId2, serviceId] = [nullnullnull, '04C4B00D-E33F-4B50-8797-0A2B47F9F98E'];
  2. wx.closeBluetoothAdapter({
  3.   complete() {
  4.     wx.openBluetoothAdapter({
  5.       complete(res) {
  6.         // 此处不用errCode的原因是:目前小程序苹果手机返回成功时没有errCode字段,应该是小程序的bug
  7.         if (res.errMsg === 'openBluetoothAdapter:ok') {
  8.           // 蓝牙初始化成功(此处调用蓝牙搜索api)
  9.         } else {
  10.           // 蓝牙初始化失败
  11.         }
  12.       }
  13.     });
  14.   }
  15. });

2、开启蓝牙搜索

  1. wx.startBluetoothDevicesDiscovery({
  2.   services: [serviceId], // 此处放置指定的搜索id
  3.   complete(res) {
  4.     if (res.errCode === 0) {
  5.       // 蓝牙搜索正常(此处调用蓝牙发现指定设备api)
  6.     } else {
  7.       // 蓝牙搜索故障
  8.     }
  9.   }
  10. });

3、发现指定设备

  1. wx.onBluetoothDeviceFound(res => {
  2.   if (!res.devices.length) {
  3.     // 没有搜到设备
  4.   } else {
  5.     // 搜到设备,保存设备deviceId(此处调用蓝牙连接api)
  6.     deviceId = res.devices[0].deviceId;
  7.   }
  8. });

4、连接指定设备

  1. wx.createBLEConnection({
  2.   deviceId,
  3.   complete(res) {
  4.     if (res.errCode === 0) {
  5.       // 指定设备连接成功(此处调用关闭蓝牙搜索api和获取设备服务api)
  6.     } else {
  7.       // 指定设备连接失败
  8.     }
  9.   }
  10. });

5、获取设备服务

  1. wx.stopBluetoothDevicesDiscovery();
  2. wx.getBLEDeviceServices({
  3.   deviceId,
  4.   complete(res) {
  5.     if (res.errCode === 0) {
  6.       // 获取设备服务成功(此处调用蓝牙获取服务特征值api)
  7.       serviceId = res.services[0].uuid;
  8.     } else {
  9.       // 获取设备服务失败
  10.     }
  11.   }
  12. });

6、获取服务特征码

  1. wx.getBLEDeviceCharacteristics({
  2.   deviceId,
  3.   serviceId,
  4.   complete(res) {
  5.     if (res.errCode === 0) {
  6.       // 获取设备服务特征码成功(此处调用蓝牙订阅notify特征值api和接收指令api)
  7.       // characteristicId用于发送指令,characteristicId2用于接收指令
  8.       characteristicId = res.characteristics.find(item => item.properties.write).uuid;
  9.       characteristicId2 = res.characteristics.find(item => !item.properties.write).uuid;
  10.     } else {
  11.       // 获取设备服务特征码失败
  12.     }
  13.   }
  14. });

7、发送指令

  1. wx.writeBLECharacteristicValue({
  2.   deviceId,
  3.   serviceId,
  4.   characteristicId,
  5.   value: str2ab('web:' + Math.random()),
  6.   complete(res) {
  7.     if (res.errCode === 0) {
  8.       // 指令发送成功
  9.     } else {
  10.       // 指令发送失败
  11.     }
  12.   }
  13. });

8、订阅notify特征值并接收指令

  1. wx.notifyBLECharacteristicValueChange({
  2. state: true,
  3. deviceId,
  4. serviceId,
  5. characteristicId: characteristicId2,
  6. complete(res) {
  7. // 此处可能回报10008的错误,不过不影响设备间正常通讯,猜测可能是小程序的bug
  8. }
  9. });
  10. wx.onBLECharacteristicValueChange(res => {
  11. // 此处处理接收到的指令
  12. console.log('onBLECharacteristicValueChange', ab2str(res.value))
  13. });

特别提醒:在发送指令和接收指令时,分别要使用函数(下面两个函数)转换一下,否则程序会报错或解析乱码

  1. // ArrayBuffer转字符串
  2. function ab2str(buf) {
  3.   return String.fromCharCode.apply(nullnew Uint8Array(buf));
  4. }
  5. // 字符串转ArrayBuffer
  6. function str2ab(str) {
  7.   let buf = new ArrayBuffer(str.toString().length);
  8.   let view = new Uint8Array(buf);
  9.   for (let i = 0; i < str.length; i++) {
  10.     view[i] = str.charCodeAt(i);
  11.   }
  12.   return buf;
  13. }

7、小程序钩子函数

小程序的钩子函数一共分为两种:app部分和page部分

app部分有3个:

onLaunch:小程序初始化。

onShow:小程序启动,或从后台进入前台显示。

onHide:小程序从前台进入后台。

page部分有10个:

onLoad:页面加载时触发。一个页面只会调用一次,可以在onLoad的参数中获取打开当前页面路径中的参数。

onShow:页面显示/切入前台时触发,每次页面打开都会调用一次。

onReady:页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。对界面内容进行设置的API如wx.setNavigationBarTitle,请在onReady之后进行。

onHide:页面隐藏/切入后台时触发。如navigateTo或底部tab切换到其他页面,小程序切入后台等。

onUnload:页面卸载时触发。如redirectTo或navigateBack到其他页面时。

onPullDownRefresh:监听用户下拉刷新事件。需要在配置中开启enablePullDownRefresh。当数据刷新处理完成后,需配合wx.stopPullDownRefresh通知当前页面的下拉刷新。

onReachBottom:监听用户上拉触底事件。可以在配置中配置触发距离onReachBottomDistance。在触发距离内滑动期间,本事件只会被触发一次。

onPageScroll:监听用户滑动页面事件。

onShareAppMessage:监听用户点击页面内转发按钮<button open-type="share"></button>或右上角菜单“转发”按钮的行为,并自定义转发内容。只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮。

onTabItemTap:点击tab时触发。

欢迎留言分享你在开发小程序项目的过程中遇到什么问题。

欢迎体验笔者个人小程序

微信小程序开发常见问题微信小程序开发常见问题
shaw

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: