废话不多说,直奔主题。感谢TX团队赞助,不然没机会通宵!以下思路,仅供参考。
公告开山
改造原有授权逻辑
原来通过getUserProfile接口拿到userinfo数据,仍然不变。仅对返回结果加一次判断;
wx.getUserProfile && wx.getUserProfile({
lang: 'zh_CN',
desc: "desc",
success: ({
userInfo
}) => {
if (userInfo?.nickName === '微信用户') {
// 跳转至新建的资料修改页面
return
}
// 同步用户资料信息
api.updateUserinfo(userInfo)
},
fail: (error) => {
// 跳转至新建的资料修改页面
}
})
资料修改页面
页面
此处需要注意的是, 头像组件有最低版本兼容要求。而昵称填写则可以忽略版本兼容性。此处不赘述昵称填写
兼容性处理
data: {
supportAvatarInput: compareVersion(version, '2.21.2') >= 0,
}
<!-- 代码有省略,见下 -->
<button wx:if="{{supportAvatarInput}}" open-type="chooseAvatar"></button>
<button wx:else></button>
页面美化
由于官方没有直接提供头像选择效果的组件可供直接使用,而是以button的形式。因此需要我们自行处理,不过也很简单position + opacity即可;
先上效果图:
<view class="__input-wrapper">
<image class="avatar" src="{{avatarUrl}}"></image>
<button wx:if="{{supportAvatarInput}}" class="opacity-button" open-type="chooseAvatar"
bind:chooseavatar="onChooseAvatar"></button>
<button wx:else class="opacity-button" catchtap="handleChooseImage"></button>
</view>
.__input-wrapper{
position: relative;
top: 0;
left: 0;
}
.__input-wrapper .avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
}
.__input-wrapper .opacity-button{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9;
opacity: 0;
padding: 0 !important;
margin: 0 !important;
}
到此,界面完工。接下来开始处理头像上传问题。
业务逻辑
先来处理头像上传组件本身的事件,
此处有个坑。官方的头像上传不支持裁剪,因此需要用到更新的cropImage这个API。
所以我们先来实现图片裁剪功能, 依然是注意兼容性。因为目前是从2.26.0才开始支持。
cropAvatar(url){
return new Promise((resolve, reject) => {
try {
if (wx.cropImage) {
wx.cropImage({
src: url,
cropScale: "1:1",
success({
tempFilePath
}) {
if (!tempFilePath) return reject(Error('处理失败,未获取到路径'))
resolve(tempFilePath)
},
fail(error) {
reject(Error(error.errmsg || error.errMsg))
}
})
return
}
// 低版本兼容
// 此处可弹窗提醒用户手动裁剪为1:1
if (wx.editImage) return wx.editImage({
src: url,
success({
tempFilePath
}) {
if (!tempFilePath) return reject(Error('处理失败,未获取到路径'))
resolve(tempFilePath)
},
fail(error) {
reject(Error(error.errmsg || error.errMsg))
}
})
// 其他情况返回原url
resolve(url)
} catch (error) {
reject(error)
}
})
}
考虑到用户上传的图片可能会很大。也可以继续设计一个压缩图片的方法。
此处又是一个坑,官方的compressImage API模拟器上会返回错误的tempFilePath方法(真机目前没有)
compressImage(url){
return new Promise(async (resolve, reject) => {
// 指定压缩为480px * 480px
const COMPRESS_SIZE = 480
try {
const {
width,
height
} = await this.getImageInfo(url)
const size = Math.ceil(Math.sqrt(width * height))
if (size <= COMPRESS_SIZE) throw Error(`当前图片尺寸为 ${width} * ${height} (${size}) , 已符合压缩规则,忽略压缩`)
const quality = Math.ceil(COMPRESS_SIZE * 100 / size)
if (!wx.compressImage) throw Error("当前基础库版本太低,请升级微信客户端")
wx.showLoading({
title: '压缩中',
})
wx.compressImage({
src: url,
quality: quality,
// 以下高版本支持,低版本仍考虑 quality
compressedWidth: COMPRESS_SIZE,
compressHeight: COMPRESS_SIZE,
success({
tempFilePath
}) {
if (!tempFilePath) return reject(Error('处理失败,未获取到路径'))
// 检查后缀是否存在, 应对模拟器返回错误的tempFilePath问题
if (!/^.*\.(.+)$/.test(tempFilePath)) return reject(Error('SDK错误,压缩路径不正确'))
resolve(tempFilePath)
},
fail(error) {
reject(Error(error.errmsg || error.errMsg))
},
complete() {
wx.hideLoading({})
}
})
} catch (error) {
reject(error)
}
})
}
到此准备工作已就绪。 新坑来袭
又一个坑, 此处通过头像上传的url并非和之前一样。这次的是个临时链接,不能直接存储至数据库使用。因此需要服务端提供头像上传的接口。前端调用wx.uploadFile API上传。 此处不赘述
处理头像组件的回调
async onChooseAvatar({
detail
}) {
let url = detail.avatarUrl
// 裁剪
url = await this.cropAvatar(url)
// 压缩
try {
url = await this.compressImage(url)
} catch (error) {
console.error('头像压缩失败:', error)
}
try {
// 此处是上传接口调用。 根据自己需要改造即可
const { avatarUrl } = await app.$http.post({
url: '/upload',
header: {
'content-type': 'multipart/form-data'
},
data: {
name: 'picture',
filePath: url,
},
timeout: 30 * 1000,
loading: '上传中'
})
this.setData({
avatarUrl: avatarUrl
})
app.$Toast("上传成功")
} catch (error) {
wx.showModal({
content: `${error.message || "上传失败,请稍后再试"}`,
showCancel: false
})
}
}
别忘了还有个低版本的适配, 这个简单。 不过这个还是有低版本兼容处理
handleChooseImage() {
try {
let self = this
if (wx.chooseMedia) {
return wx.chooseMedia({
count: 1,
mediaType: 'image',
async success(res) {
const tempFilePath = res?.tempFiles[0]?.tempFilePath
if (!tempFilePath) return app.$Toast("选取失败,请稍后再试")
// 此处复用之前的头像上传回调
await self.onChooseAvatar({
detail: {
avatarUrl: tempFilePath
}
})
},
fail() {
app.$Toast("头像修改失败 请稍后再试")
}
})
}
wx.chooseImage({
count: 1,
async success(res) {
const tempFilePath = res?.tempFilePaths[0]
if (!tempFilePath) return app.$Toast("选取失败,请稍后再试")
await self.onChooseAvatar({
detail: {
avatarUrl: tempFilePath
}
})
},
fail() {
app.$Toast("头像修改失败 请稍后再试")
}
})
} catch (error) {
app.$Toast("当前版本太低,建议您先升级微信客户端")
}
},
总结
希望这是最后一次
- 低版本兼容性要注意, 狂放的小伙伴可以设置最低版本库,一劳永逸
- 头像和昵称组件,自带了安全识别功能。因此会比较慢,需要吐槽的是头像图片的鉴黄识别有点拉跨,经常误报。 如果你看到提示”当前头像不可用“之类的提示,不要担心是代码问题
- 图片裁剪API才出, 所以在此之前官方是没有考虑到的。吐血
- 官方其他的bug也该修修了,就比如compressImage里模拟器返回的路径
写的仓促,如有不对,请多指正!
一点小宣传
已经第一时间接入cropImage了,很香。 欢迎体验!!
附小程序码:
体验路径 : 我的 -> 左上角”设置“ -> 个人信息修改
感谢,把最近的坑填上了🥹,但是我的华为P60它就是获取不到头像也登录不了,其他手机都可以,我怀疑是手机太新了或者是鸿蒙的兼容性问题😭
无聊的改造,不陪微信玩了