炎炎的夏日一起来为头像增加点夏天的元素,让清爽的头像陪伴你一整个夏天。通过一个完整的小程序串通整个开发生命周期。
开发一款可以为头像增加夏日元素贴纸的小程序。支持直接使用用户当前头像信息,支持将制作的头像保存到用户相册。
首页模块分为未授权和已授权使用用户信息两种状态,当用户刚进入页面未操作的情况下提供授权的操作按钮,当用户完成授权后展示头像制作的视图。
微信小程序注册流程包括账号信息填写、邮箱激活、信息登记三个步骤,按网站提示注册即可。
Tips:
使用微信开发者工具创建一个不使用任意模板的项目并按照下面的目录约定进行少许调整,见注释的特别约定:
CoolAvatar
├─app.js // 默认约定:app主函数
├─app.json // 默认约定:窗口、页面、组件配置
├─app.wxss // 默认约定:app全局样式定义文件
├─package.json // 默认约定:使用npm安装依赖后自动生成更新
├─project.config.json // 默认约定:配置npm依赖文件、文件夹、appid等
├─project.private.config.json
├─sitemap.json
├─utils // 默认约定:开发过程中用到的工具函数
| └─util.js
├─templates // 特别约定:用来放置页面用到的模板
| ├─authorization
| | ├─authorization.wxml
| | └─authorization.wxss
├─pages // 默认约定:每个页面的位置
| ├─index
| | ├─index.js
| | ├─index.json
| | ├─index.wxml
| | └─index.wxss
├─images // 特别约定:项目基础图片素材
| ├─icon-about-default.png
| ├─icon-about-selected.png
| ├─logo.png
| ├─material // 特别约定:贴纸素材
| | ├─1.png
| | └─2.png
复制代码
根据自己的喜好和习惯可以自行选择,一个顺手的UI库对于快速开发还是很有必要的,安装、配置及组件使用支持参照vant-ui组件文档即可。
Tips:
配置tabbar,满足首页和关于页面的切换。通过微信开发者工具【右键】=>【新建 Page】创建about页面后将下面的配置添加到 app.json 完成底部标签栏的配置:
属性 | 描述 |
---|---|
tabbar.color | 未选中字体颜色 |
tabbar.selectedColor | 选中的字体颜色 |
tabbar.list | 配置每个标签的内容 |
tabbar.list.text | 标签文案 |
tabbar.list.pagePath | 页面的实际路径 |
tabbar.list.iconPath | 未选中的标签ICON |
tabbar.list.selectedIconPath | 选中的标签ICON |
{
"tabBar": {
"color": "#dbdbdb",
"selectedColor": "#04cd95",
"list": [
{
"selectedIconPath": "images/icon-home-selected.png",
"iconPath": "images/icon-home-default.png",
"pagePath": "pages/index/index",
"text": "首页"
},
{
"selectedIconPath": "images/icon-about-selected.png",
"iconPath": "images/icon-about-default.png",
"pagePath": "pages/about/about",
"text": "关于"
}
]
}
}
复制代码
配置完成后结果:
因为我们存在读取用户头像并下载的操作,所以需要将微信头像的域名地址配置到downloadFile里面,开发过程中虽然可以在开发者工具设置不校验域名,但还是建议一开始就配置好:
我们主要来实现首页中夏日新头像的制作,关于页面仅展示静态文案就不过多讲述了,完整代码在文末提供。
微信小程序在开发过程中提供了模块的概念,使得我们可以将一个视图文件中的”一块“提取到单独的文件中,既能减少原视图文件中的代码量又能在可能存在复用的情况下进行复用,节省开发工作。
<template name="authorization">
<view class="get-user-info">
<van-image width="120" height="120" fit="cover" round src="url" />
<van-button color="#04cd95" plain wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile" block>Get 新头像 清爽一夏~</van-button>
</view>
</template>
复制代码
<import src="../../templates/authorization/authorization.wxml" />
<template is="authorization" data="{{canIUseGetUserProfile}}" />
复制代码
我们通过使用模板将各版块拆分到 templates 目录:
<!-- 导入模板 -->
<import src="../../templates/switch-rect/switch-rect.wxml" />
<import src="../../templates/operating-area/operating-area.wxml" />
<import src="../../templates/material-area/material-area.wxml" />
<import src="../../templates/authorization/authorization.wxml" />
<!-- 未授权提示 -->
<van-dialog message="亲,必要的权限您需要开启哦~" show="{{ isOpenSetting }}" confirm-button-text="开启" bind:confirm="handlerOpenSetting">
</van-dialog>
<!-- 合成头像画布 -->
<canvas class="userinfo-canvas" canvas-id="festivalCanvas"></canvas>
<!-- 内容主体 -->
<view class="userinfo">
<block wx:if="{{!hasUserInfo}}">
<!-- 授权区 -->
<template is="authorization" data="{{canIUseGetUserProfile}}" />
</block>
<view wx:else style="text-align: center;">
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}"></image>
<!-- 拖动贴纸 -->
<template is="switchRect" data="{{rotate,festivalSize,festivalLeft,festivalTop,festivalSrc,festivalScale}}" />
<!-- 操作区 -->
<template is="operatingArea" />
<!-- 贴纸区 -->
<template is="materialArea" data="{{material}}" />
</view>
</view>
复制代码
涉及 API:wx.getUserProfile(Object object)
用户主动触发定义的 getUserProfile
函数来打开小程序内置的授权提示窗口,在用户同意后成功拿到用户的 UserInfo 对象,从中解析到用户的头像信息,我们通过 hasUserInfo
变量的状态来控制未授权和已授权页面状态的显示。
getUserProfile(e) {
wx.getUserProfile({
desc: '展示用户头像',
success: (res) => {
const {
material
} = this.data;
this.setData({
userInfo: res.userInfo,
hasUserInfo: res.userInfo != null,
festivalSrc: material[0].url,
});
}
})
}
复制代码
在 switch-rect.wxml
模板中定义了贴纸操作的容器,并在容器中显示当前选中的贴纸素材,将容器设置固定定位后通过实时改变 css 的选中角度、宽高及边距的数据来完成。
容器事件的绑定包含了catchtouchstart、catchtouchmove、catchtouchend,右下角的选中按钮同样绑定了这三个属性。catch在这里表示会阻止事件向上冒泡事件的具体处理可以在文末的提供的源码地址查看。
涉及 API:
使用 wx.getSetting
可以得到当前用户设置列表的权限状态,通过查看指定状态是否已授权来决定能否继续执行下一步,否则我们配置来提示框口来引导用户使用 wx.openSetting
跳转到设置页面手动操作授权。
wx.getSetting({
success(res) {
if (!res.authSetting[scope]) {
wx.authorize({
scope,
success() {
callback && callback(true);
},
fail() {
self.setData({
isOpenSetting: true,
});
}
})
} else {
callback && callback(true);
}
},
fail(err) {
console.log(err)
}
})
复制代码
涉及 API:wx.saveImageToPhotosAlbum
通过调用封装的 saveImage
函数,传入 canvasid 和尺寸数据可以得到合成后的图像信息。再调用 wx.saveImageToPhotosAlbum
将图像信息保存到用户的手机相册,至此首页功能的 MVP 版本就完结了~
saveImage(this.data, res.tempFilePath, {
canvasid: 'festivalCanvas',
width: 700,
height: 700,
offsetTop: 0,
offsetLeft: 0,
}, (img) => {
wx.hideLoading();
if (img) {
this.saveImageToPhotosAlbum(img)
}
});
复制代码
在微信开发者工具中有一个代码质量检查的功能,我们可以通过提示的处理方案进行操作,我们这个小程序没有使用CDN来放贴纸素材,所以图片资源超出了默认的200k的限制,有条件的时候可以优化一下~。
这里的推送代码指的是通过微信开发者工具将编写的代码打包上传到小程序平台做发布,并非代码管理~。
推送代码后就可以在这里查看到了,核实没有问题就提交审核后耐心等待吧。
等审核通过后就可以再次来到小程序平台执行提交发布的操作了,发布以后可以先用过扫描进入正式版小程序,稍后才能在微信搜索到。
Q: 在使用 van-button 的时候发现通过在 app.wxss
中使用重新编写 css 类无法正常覆盖样式;
A:在 .van-button
前增加 view 标识可以完成,如下;
view .van-button {
height: 75rpx;
}
复制代码
Q:尝试在 onload 后直接调用 wx.getUserProfile 函数来减少操作,但没有正常弹出窗口?
A:页面设计未授权状态,让用户主动触发才能正常弹窗。
Q:在获取到用户的头像信息后发现头像特别模糊,完全无法进行新头像的成?
A:UserInfo在说明 avatarUrl 提到了地址最后一段的含义,0、46、64、96、132 数值可选,0 代表 640x640 的正方形头像,46 表示 46x46 的正方形头像,剩余数值以此类推。默认132。所以我们需要将默认的 132 替换成 0 得到最高清的一张头像。
const index = res.userInfo.avatarUrl.lastIndexOf('/132');
if (index != -1) {
res.userInfo.avatarUrl = res.userInfo.avatarUrl.substring(0, index) + '/0';
}
复制代码
Q:应开发用户自行拍照或上传相册中的图片来制作头像,为啥没有这个功能?
A:目前微信小程序提供的 wx.editImage(Object object)不支持按比例裁剪,这样的功能居然是准备酌情增加,非 1:1 的头像在选择后的效果太差。上面提到的参考项目中有关于等比例裁剪的实现,感兴趣的小伙伴可以尝试。
Q:在开发中相册选择的图像和授权得到的用户头像有什么区别,可以直接使用么?
A:我们在画布中操作的图片都是图像本身,授权得到的用户头像仅是图像的地址,所以我们需要使用 wx.downloadFile(Object object) 函数将头像资源下载后使用。
Q:我也使用的项目来整合视图,可以样式为啥没有生效呢?
A:在微信小程序的开发文档有关于模板的使用但未提供样式的处理,我们需要在目标视图的 wxss 文件中使用 @import
导入模板的样式。
第一次完整的小程序开发到上线就到此结束了,可以在微信搜索”夏日贴纸头像“来为自己的头像做一次换装吧。
在体验了原生的小程序开发和跨小程序平台的开发模式后感觉还是原生的体验要更好,跨平台的支持在中间层转换的稳定性还有待提升,要不也不至于一个白屏的问题是通重新CV了一遍就搞定的吧~