背景
2019年10月1日,在祖国70周年大庆前夕,微信、朋友圈人纷纷要求@微信正式国旗的情景被刷屏,在庆祝祖国生日的同时玩得很开心。
9月25日,我决定在国庆节前开发改变头发的微信小程序,举行祖国70周年献礼。最终,国庆节前一天在网上发布了制作头像的小程序“海豚趣味图”,帮助10000多名小伙伴成功更改国旗头像。
小程序已经在线,但我希望能总结一下【海豚趣味图】这个小程序开发过程中有趣的技术要点,与大家分享。
主要阶段
用户简介照片模板图片创建获取用户简介
创建自定义头像的第一步是首先选择照片。在[海豚有趣的图片]的交互设计中,用户可以通过微信头像、本地相册、相机拍摄等三种方式选择照片。获得用户头像的产品设计如下图所示。
微信当局不再支持通过wx.getUserInfo接口获取用户信息,因此必须使用button组件并将open-type指定为getUserInfo类型以获取或显示用户信息。
为了优化用户体验,逐渐不支持使用wx.getUserInfo界面直接弹出身份认证框的开发方法。从2018年4月30日开始,小程序和迷你游戏的体验版、开发版调用wx.getUserInfo界面时,授权问题框不会弹出,默认调用失败。正式版本暂时不受影响。
上图中弹出式下部菜单的交互方式不能通过wx.showActionSheet执行(因为接口只能指定字符串文本,而不能使用button、navigator等组件)。
因此,这些功能只能通过自定义actionSheet组件来实现。
Mmp-action-sheet组件
以下是mmp-action-sheet组件的代码:
Index.wxml
View hidden='{!action show } } ' class=' mask { { mask } } ' bindtap=' action hide '
view class=' action sheet animated { { animation } } '
插槽/插槽
button class=' close ' bindtap=' action hide ' { close text } }/button
/view
/view
通过Slot将自定义内容(如button、navigator等)插入到活动表中。
Index.wxss
.mask{
Position: fixed:
塔: 0;
左边: 0;
width :100%;
海特: 100%;
Background: rgba(0,0,0,0 . 5);
Z-索引: 999;
}
.actionSheet{
width : 100%;
Position: absolute:
top : 100%;
Z-索引: 1000;
Overflow: hidden
}
.actionSheet button、
.actionSheet navigator{
Color: # 000
文本-align :中心:
Background: # fff
border-radius : 0;
line-height : 3.5;
font-size : 32 rpx;
Border-bottom : 1 rpx固态RGB (236,236,236);
OPACITY : 1;
}
.actionSheet button:active、
.action sheet navigator : active {
Color: # 000
Background: rgb(236、236和236);
}
.actionsheetbutton :3360适配器、
.actionShee
t navigator::after { border: none; border-radius: 0; } .actionSheet .close{ border-bottom: none; border-bottom: 50rpx solid #fff; border-top: 16rpx solid rgb(236, 236, 236); } .animated { animation-timing-function: ease-out; animation-duration: 0.2s; animation-fill-mode: both; } @keyframes fadeInBottom { from{ transform: translate3d(0, 0, 0); } to { transform: translate3d(0, -100%, 0); } } .fadeInBottom { animation-name: fadeInBottom; } @keyframes fadeOutBottom { from{ transform: translate3d(0, -100%, 0); } to { transform: translate3d(0, 0, 0); } } .fadeOutBottom { animation-name: fadeOutBottom; } @keyframes fadeIn { from{ opacity: 0; } to { opacity: 1; } } .fadeIn { animation-name: fadeIn; } @keyframes fadeOut { from{ opacity: 1; } to { opacity: 0; } } .fadeOut { animation-name: fadeOut; } index.js Component({ properties: { actionSheetStatus: { type: Boolean, value: false, observer(newVal) { if (newVal) { ({ actionSheetStatus: true, animationMask: 'fadeIn', animationSheet: 'fadeInBottom' }) } else { ({ actionSheetStatus: false, animationMask: 'fadeOut', animationSheet: 'fadeOutBottom' }) } } }, closeText: { type: String, value: '取消' } }, data: { animationMask: 'fadeIn', animationSheet: 'fadeInBottom' }, methods: { closeActionSheet() { ({ animationMask: 'fadeOut', animationSheet: 'fadeOutBottom' }) setTimeout(() => { ({actionSheetStatus: false}) }, 300) } } })组件只有两个参数:
- actionSheetStatus 指定组件的初始展示状态,默认为false,表示不显示组件。
- closeText 指定关闭按钮的名字,默认为 取消。
index.json
{ "component": true, "usingComponents": {} }接下来在页面中调用组件,在组件中插入了3个 button 组件来实现来获取用户头像:
<action-sheet actionSheetStatus="{{actionSheetStatus}}"> <button open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">使用微信头像</button> <button bindtap="pickPic" data-source-type="album">使用本地相册</button> <button bindtap="pickPic" data-source-type="camera">拍照</button> </action-sheet>以上我们通过自定义组件 mmp-action-sheet 就解决了原生的 actionsheet 无法指定 button,从而无法获取用户微信头像的问题。
该组件我已经发布到 npm 包,需要用到的同学可以通过 npm 安装,也可以在 github 上查看源码和使用文档。
图片模板
有了原图,接下来我们需要选择图片模板。如果模板数量不多或者模板变化不频繁,我们可以直接把模板放在本地。鉴于我提供的模板比较多,放在本地会增大小程序源码的大小,我把模板上传到了小程序的云存储中,通过云函数来动态获取图片模板,方便以后模板扩展。
云函数 tpl 的代码如下:
// 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init() // 云函数入口函数 ex = async (event, context) => { const wxContext = cloud.getWXContext() // 1. 获取数据库引用 const db = cloud.database() const MAX_LIMIT = 100 // 2. 构造查询语句 const countResult = await db.collection('template').count() const total = coun // 计算需分几次取 const batchTimes = Ma(total / 100) const tasks = [] for (let i = 0; i < batchTimes; i++) { const promise = db.collection('template').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get() (promise) } return (await Promi(tasks)).reduce((acc, cur) => { return { data: acc.da), errMsg: acc.errMsg, } }) }页面中调用云函数拉取模板:
getTpl() { const self = this // 调用云函数获取图片模板 wx.cloud.callFunction({ name: 'tpl' }).then(res => { ({ templates: res.re }) }) }问题
到这里模板的获取逻辑已经没有问题了,但在开发过程中遇到了一个问题。模板图片的链接我使用的是云文件ID,当有大量图片并行加载的时候,只有部分图片能够显示,我看了一下dom节点其实都已经存在了,image的src的地址也都是正确的。
微信官方自2.3.0开始已经支持在image中使用云文件ID。云文件ID的格式为: cloud://xxx.xxx/templates/01.png。
我猜测可能是对微信云存储并发请求过多导致的(有知道的同学可以告知),因为我试了一下将云文件ID换成正常的HTTPS的链接是没问题的。
由此可知,可以想到有三种可行的解决方案:
- 将图片模板存储到外部OSS,使用https协议的链接。
- 使用 wx.getTempFileURL 用云文件 ID 换取真实链接,也就是https形式的链接。
- 控制图的并行加载数量。我的实践是将并行加载数量控制在20,当用户滚动的时候再发起下一次请求。
总结
以上主要分享了用户头像获取以及图片模板功能的实现及所遇到的一些问题。关于图片的合成是整个小程序的核心功能,下一篇单独拉出来说一下实现思路和潜在的问题。敬请期待!
扫码体验
读者可以扫码体验我们所讲述的两个功能点:
- 自定义actionsheet组件
- 图片模板加载