2019年10月1日在祖国70周年大庆之际,微信朋友圈被你们纷纷@微信官方要国旗的景象给刷屏了,在为祖国庆生的同时,玩的不亦乐乎。前端
在9月25日,我心血来潮决定在国庆前开发一个换头像的微信小程序为祖国70周年献礼!最终在国庆前夕上线发布了制做头像的小程序-【海豚趣图】,帮助10000多名小伙伴成功换上了国旗头像。git
小程序虽然已经上线,但在【海豚趣图】这个小程序开发过程当中的一些有意思的技术点我但愿能总结一下和你们进行分享。github
制做自定义头像的第一步就是先选择图片。在【海豚趣图】的交互设计中,用户有三种选择图片的方式:微信头像、本地相册和相机拍摄。获取用户头像的产品设计以下图所示:数据库
因为微信官方再也不支持经过 wx.getUserInfo 接口来获取用户信息,咱们必须经过使用 button
组件并将 open-type
指定为 getUserInfo
类型来获取或展现用户信息。npm
为优化用户体验,使用 wx.getUserInfo 接口直接弹出受权框的开发方式将逐步再也不支持。从2018年4月30日开始,小程序与小游戏的体验版、开发版调用 wx.getUserInfo 接口,将没法弹出受权询问框,默认调用失败。正式版暂不受影响。json
上图中弹出底部菜单的交互方式没法经过 wx.showActionSheet
来实现(由于该接口只能指定字符串文本,不能使用 button
, navigator
等组件)。小程序
所以,只能经过自定义 actionSheet
组件来实现以上功能。微信小程序
如下是 mmp-action-sheet 组件的代码。promise
<view hidden="{{!actionShow}}" class="mask {{mask}}" bindtap="actionHide">
<view class="actionSheet animated {{animation}}">
<slot></slot>
<button class="close" bindtap="actionHide">{{closeText}}</button>
</view>
</view>
复制代码
经过 slot
在 action-sheet 中插入自定义的内容,好比 button
、navigator
等。bash
.mask{
position: fixed;
top: 0;
left: 0;
width:100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
}
.actionSheet{
width: 100%;
position: absolute;
top: 100%;
z-index: 1000;
overflow: hidden;
}
.actionSheet button,
.actionSheet navigator{
color: #000;
text-align: center;
background: #fff;
border-radius: 0;
line-height: 3.5;
font-size: 32rpx;
border-bottom: 1rpx solid rgb(236, 236, 236);
opacity: 1;
}
.actionSheet button:active,
.actionSheet navigator:active{
color:#000;
background: rgb(236, 236, 236);
}
.actionSheet button::after,
.actionSheet 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;
}
复制代码
Component({
properties: {
actionSheetStatus: {
type: Boolean,
value: false,
observer(newVal) {
if (newVal) {
this.setData({
actionSheetStatus: true,
animationMask: 'fadeIn',
animationSheet: 'fadeInBottom'
})
} else {
this.setData({
actionSheetStatus: false,
animationMask: 'fadeOut',
animationSheet: 'fadeOutBottom'
})
}
}
},
closeText: {
type: String,
value: '取消'
}
},
data: {
animationMask: 'fadeIn',
animationSheet: 'fadeInBottom'
},
methods: {
closeActionSheet() {
this.setData({
animationMask: 'fadeOut',
animationSheet: 'fadeOutBottom'
})
setTimeout(() => {
this.setData({actionSheetStatus: false})
}, 300)
}
}
})
复制代码
组件只有两个参数:
actionSheetStatus
指定组件的初始展现状态,默认为false,表示不显示组件。closeText
指定关闭按钮的名字,默认为 取消
。{
"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()
// 云函数入口函数
exports.main = 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 = countResult.total
// 计算需分几回取
const batchTimes = Math.ceil(total / 100)
const tasks = []
for (let i = 0; i < batchTimes; i++) {
const promise = db.collection('template').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
tasks.push(promise)
}
return (await Promise.all(tasks)).reduce((acc, cur) => {
return {
data: acc.data.concat(cur.data),
errMsg: acc.errMsg,
}
})
}
复制代码
页面中调用云函数拉取模板:
getTpl() {
const self = this
// 调用云函数获取图片模板
wx.cloud.callFunction({
name: 'tpl'
}).then(res => {
self.setData({
templates: res.result.data
})
})
}
复制代码
到这里模板的获取逻辑已经没有问题了,但在开发过程当中遇到了一个问题。模板图片的连接我使用的是云文件ID,当有大量图片并行加载的时候,只有部分图片可以显示,我看了一下dom节点其实都已经存在了,image的src的地址也都是正确的。
微信官方自2.3.0开始已经支持在image中使用云文件ID。云文件ID的格式为:
cloud://xxx.xxx/templates/01.png
。
我猜想多是对微信云存储并发请求过多致使的(有知道的同窗能够告知),由于我试了一下将云文件ID换成正常的HTTPS的连接是没问题的。
由此可知,能够想到有三种可行的解决方案:
wx.getTempFileURL
用云文件 ID 换取真实连接,也就是https形式的连接。以上主要分享了用户头像获取以及图片模板功能的实现及所遇到的一些问题。关于图片的合成是整个小程序的核心功能,下一篇单独拉出来讲一下实现思路和潜在的问题。敬请期待!
读者能够扫码体验咱们所讲述的两个功能点:
快狗打车前端团队专一前端技术分享,按期推送高质量文章,欢迎关注点赞。 文章同步发布在公众号哟,想要第一时间获得最新的资讯,just scan it !