评论

[干货]新一轮用户授权改版来了,肝起来吧!

为10月25而战,一起肝起来! 一起交流头像昵称获取规则调整的”后遗症“!

废话不多说,直奔主题。感谢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("当前版本太低,建议您先升级微信客户端")
    }
},

总结

希望这是最后一次

  1. 低版本兼容性要注意, 狂放的小伙伴可以设置最低版本库,一劳永逸
  2. 头像和昵称组件,自带了安全识别功能。因此会比较慢,需要吐槽的是头像图片的鉴黄识别有点拉跨,经常误报。 如果你看到提示”当前头像不可用“之类的提示,不要担心是代码问题
  3. 图片裁剪API才出, 所以在此之前官方是没有考虑到的。吐血
  4. 官方其他的bug也该修修了,就比如compressImage里模拟器返回的路径

写的仓促,如有不对,请多指正!

一点小宣传

已经第一时间接入cropImage了,很香。 欢迎体验!!

附小程序码:

体验路径 : 我的 -> 左上角”设置“ -> 个人信息修改

大家还有什么想说的! 欢迎评论区交流

最后一次编辑于  2023-02-13  
点赞 4
收藏
评论

2 个评论

  • E88D89
    E88D89
    2023-04-06

    感谢,把最近的坑填上了🥹,但是我的华为P60它就是获取不到头像也登录不了,其他手机都可以,我怀疑是手机太新了或者是鸿蒙的兼容性问题😭

    2023-04-06
    赞同 1
    回复
  • Victor
    Victor
    发表于小程序端
    2022-09-08

    无聊的改造,不陪微信玩了

    2022-09-08
    赞同 1
    回复
登录 后发表内容