- 可以支持异步 setData 吗?
目前在 async/await 中参入回调式 setData 函数显得非常别扭,举个列子,我希望在请求完成后不论成功与否都处理一些单独的业务逻辑: try { const { data: res } = await fetch.getRes('/get', { page: 1, limit: 10 }) if (res.code === 0) { this.setData({ count: res.data.count, list: res.data.list }, () => { doSomeThings1() doSomeThings2() }) } else { wx.showToast({ title: res.data.msg, icon: 'none' }) doSomeThings1() doSomeThings2() } } catch (err) { wx.showToast({ title: '服务器开小差了', icon: 'none' }) doSomeThings1() doSomeThings2() } 会看到上面出现了大量重复代码,增加代码阅读成本,降低开发效率。当然,可以单独封装一下逻辑,例如下面这样: const doThings = () => { doSomeThings1() doSomeThings2() } try { const { data: res } = await fetch.getRes('/get', { page: 1, limit: 10 }) if (res.code === 0) { this.setData({ count: res.data.count, list: res.data.list }, doThings) } else { wx.showToast({ title: res.data.msg, icon: 'none' }) doThings() } } catch (err) { wx.showToast({ title: '服务器开小差了', icon: 'none' }) doThings() } 这时候仍然可以看到出现了三次重复的逻辑。 如果有 setDataAsync 方法,代码看上去会像下面这样更加简洁: try { const { data: res } = await fetch.getRes('/path', { page: 1, limit: 10 }) if (res.code === 0) { await this.setDataSync({ count: res.data.count, list: res.data.list }) } else { wx.showToast({ title: res.data.msg, icon: 'none' }) } } catch (err) { wx.showToast({ title: '服务器开小差了', icon: 'none' }) } doSomeThings1() doSomeThings2() 当然,也许可以自己定义一个 setDataAsync 方法,像这样: Page({ /** * 异步设置数据 * @param {Record<string, any>} data * @returns {Promise<void>} */ setDataAsync(data) { return new Promise(resolve => void this.setData(data, resolve)) } }) 可是上面这么做存在一些问题: 每个页面/组件都需要手动写上该方法,仍然会增加大量的重复代码。结合 TypeScript 时,无法和 setData 一样获得良好的代码补全(setData 方法可以获得在 data 中定义的属性并自动补全)。 以上是目前我开发时遇到的问题,目前能想到的方案是支持异步 setData,可以考虑两种方式: 让原有的 setData 返回 Promise,原有 callback 保持不变。新增 setDataAsync 异步方法。个人认为第一种方式更好些,希望开发团队考虑下。
2022-03-28 - 用户引导组件开发(2)遮罩层与突出元素
我们一步步来吧,包括我踩过的坑我也会还原一遍,让大家一起长长见识 遮罩层 遮罩层是最没技术难度的,写个css就可以了。 .mask { z-index: 1110; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); } 按然后再加个bindtap,控制点击之后消失,感觉直接就可以用了呢。这里有铅笔画不出蜡笔的味道提供的一个代码片段: https://developers.weixin.qq.com/s/cvqEYzmM7Ffn 突出元素 这个才是难点所在。 1、确定元素位置。 我们首先要找出这个元素的轮廓,这个我是通过boundingClientRect实现的。 const query = wx.createSelectorQuery(); query.select("#gameInfo").boundingClientRect(); //gameInfo就是我们所需要突出展示的元素ID,后续可以用config传入 query.exec(function(res) { console.log(res); } 输出如下: [图片] 可以看到这个办法很好地取到了所要突出的元素的位置。 2、画出镂空遮罩。 这里我参考了这篇文章:https://www.cnblogs.com/mxdmg/p/10427605.html 文章中的方法一就不说了,又麻烦又浪费空间。 方法二我试了下,展示效果确实不错,但是也如文中所说的,点遮罩的时候会点到底下的元素,肯定会影响效果。 方法三没试,因为感觉有跟二一样的缺点。 方法四也没试,因为一看就知道很麻烦。 方法五把我导向了mask-image,想说能否用这个css属性在遮罩层上挖个洞出来。关于这方面的应用我觉得这篇文章写得挺好的:https://www.zhangxinxu.com/wordpress/2017/11/css-css3-mask-masks/。然而一一试过后,发现这个属性在小程序中好像用不了(也有可能是我哪里出错,反正就是没法生效)。 呵呵。。。以上几种方式折腾了一个晚上。 后来想想,干脆抛开幻想抛开依赖,自力更生。 不搜了,自己土办法画一个。 [图片] 我用四个view作为遮罩,框出了需要突出的元素。 <view wx:if="{{showGuide}}" class="mask" bindtap="getHidden"> <view class="mask_block" style="width:100%;top:0px;left:0px;height:{{showArea.top}}px"></view> //上 <view class="mask_block" style="width:100%;top:{{showArea.bottom}}px;left:0px;height:100%"></view> //下 <view class="mask_block" style="height:{{showArea.height}}px;top:{{showArea.top}}px;left:0px;width:{{showArea.left}}px"></view> //左 <view class="mask_block" style="height:{{showArea.height}}px;top:{{showArea.top}}px;left:{{showArea.right}}px;width:100%"></view> //右 </view> 上面的showArea就是第一步中取到的元素位置。 这样一来,遮罩中的元素突出就解决了。 3、还有一个坑 本来以为这一步搞定的时候,发现这个镂空的位置竟然还会漂移!在开发工具和真机中的位置不一样,就算同在真机中,这次展示和下次展示的位置也有可能不一样! 这TM是薛定谔的镂空框! [图片] 这就是当时的神奇漂移。 经验告诉我,会出现这种不确定性的—— 十之八九都和元素的加载是否完成有关系 请好好记住这句话,可以节省你至少一天的调试时间。 是的,坑就在于步骤一的 query.select("#gameInfo").boundingClientRect(); 什么时候取的很关键。在小程序布局完成前,你可能会取到一个偏差值,导致了后面的踩坑。 我之前是在组件生命周期(还不清楚组件生命周期的看这里)中attached环节执行,不行。发现手册中还有一个ready,感觉和page中的onReady是一个东西,然而还是不行。。。 看来还是必须等页面的onReady触发之后才能取到完全正确的值。 所以我必须在主页面的onReady事件发生后再来做这个事情。 那么如何确定onReady呢?相当于我必须能够在onReady事件中去调用用户引导组件的初始化函数。。。想来想去,他们两者之间能够互动的也只有setData了。 也就是数据监听器,不懂的点这里。 幸好按计划本来也是要传入配置数组的。于是在pages中的onReady传入配置数组,然后在组件中对配置数组进行监听。 observers: { 'config': function(config) { if (config) { this.initMask(config); } } } 如此一来,遮罩层跟元素的突出展示就算完成了。 当然,这样的遮罩层还是有些不足的,例如只支持方形镂空,如果是圆形元素看着就不那么美观。。。好在我目前没有这方面需求,以后有遇到再说吧。
2020-05-10 - 用户引导组件开发(1)理下思路
个人开发者一枚。。之前为了偷懒,做的小程序都没有好好地做用户引导,导致新用户上手的不多。 所以这次下决心好好地做一个用户引导。以下是最终效果(当然,我目前还没上新版本,所以你就算找到这个小程序也看不到这个效果): [图片] 初步设想 做之前,先说说我想做成怎样的。 1、要井水不犯河水。我的几个小程序功能都已经做全了,我不想再为了这个用户引导功能去大改里面的逻辑,包括页面啥的。所以用户引导的功能实现最好能独立模块,与原来的代码尽量低耦合。 2、要能复用。用户引导可能会在各个小程序的不同页面中出现,所以必须能够复用。 因为这两个原因,做成组件是再好不过的了。把各个用户引导界面所需要展示的元素用配置数组的方式传给组件,再由组件去呈现出来。 配置数组 初步设计中,配置数组应该包括如下内容: 1、突出元素。即在遮罩层中需要突出展示的页面元素,如上面示意图中的按钮。配置数组应传入元素ID。 2、说明文字,为了美观,说明文字最好用气泡框。配置数组要传入文字内容,可能要允许多段文字,然后可以配置相关的位置大小样式。 3、说明图片。本人美工不行,但是如果是专业的团队应该会想用更生动的说明图片来替代说明文字。如以下这种的: [图片] 配置数组必须传入图片路径,且应该允许多张图片,并且可以自定义图片的位置大小等。 相关事件 遮罩层的相关事件其实很简单,就是点击。一点就没了。所以我们必须把这个事件再反馈出来。 大致想法就是这些,我们开工吧。
2020-05-10 - 小程序流量主广告收费如何计算的
有没有哪位大神知道小程序流量主功能开通后,广告是如何计费的,点击一次费用有多少? 从其他渠道得知,广告主们每次投放的最低单价是0.5元起,那么最少点击一次流量主也有0.25的收入吧,很多流量主的单价都往往低于这个价格,不知道是怎么回事呢?有没有遇到相同问题的开发者们,希望官方出来解释一下这个问题。
2019-01-02