在网上经常看到很多微信小程序换头像的,比如国庆节圣诞节等节日头像框,一键换头像,其实原理很简单,就是微信小程序授权登陆后,获取你原始头像,在你选择国旗等头像后和你授权获取头像合并生成一张新头像,另存下载。

国庆新年圣诞节日头像框小程序源码带流量主广告,加了很多素材,不喜欢素材可以自己换,采用ColorUI小程序框架,无后台。

此源码本是uniapp破解很多代码被打包过乱码的,经过站长原创改写,采用源码生JS复写。

其主要功能和逻辑

  • 授权获取微信头像

  • 头像边框分类及边框图,所有边框图必须放在远程服务器,图片太大小程序不允许

  • 选择切换头像功能,

  • 小程序canvas生成图片

image.png

image.png

XML源码:

<view class="wrapper">
    <view class="container">
        <image class="page-bg _img" mode="widthFix" src="{{bgImage}}"></image>
        <view class="avatar-container" style="{{'margin-top:'+(showHeight+'px')+';'}}" id="avatar-container">
        <!-- 屏蔽上传iocn -->
            <!-- <block wx:if="{{avatarImage}}">
                <view class="xiangji-icon"><label data-event-opts="{{[['tap',[['chooseImage',['$event']]]]]}}" class="iconfont iconxiangji2 _span" bindtap="__e"></label></view>
            </block> -->
            <image class="avatar-img _img" id="avatar-img" src="{{avatarImage}}"></image>
            <block wx:if="{{currentFrame}}">
                <image class="avatar-frame _img" src="{{frameImage}}"></image>
            </block>
            <block wx:if="{{!avatarImage}}">
                <view class="empty-avatar-view">
                    <image class="empty-avatar _img" src="/static/image/avatar_empty.svg"></image>
                    <button class="cu-btn round action-btn btn-primary" id="btn-choose-img"  bindtap="getUserProfile">获取头像</button>
                </view>
            </block>
            <view class="prev _p" wx:if="{{!avatarImage}}" bindtap="getUserProfile"><label class="iconfont iconqianfanicon _span"></label></view>
            <view class="next _p" wx:if="{{!avatarImage}}" bindtap="getUserProfile"><label class="iconfont iconhoufanicon _span"></label></view>

            <view class="prev _p" wx:if="{{avatarImage}}" data-type="pre" bindtap="cutover"><label class="iconfont iconqianfanicon _span"></label></view>
            <view class="next _p" wx:if="{{avatarImage}}" data-type="next"  bindtap="cutover"><label class="iconfont iconhoufanicon _span"></label></view>
        </view>
        <view class="_div"><canvas class="canvas" canvasId="canvas"></canvas></view>
        <view class="panel assets-container">
            <view style="display:flex;" clss="category-list" class="_div">
                <block wx:for="{{categoryList}}" wx:for-item="item" wx:for-index="index" wx:key="index">
                    <view class="_div"><text class="{{['category ',item.id===currentCategory?'active':'']}}" data-categroy-id="{{item.id}}" bindtap="imageListTab">{{item.name}}</text></view>
                </block>
            </view>
            <scroll-view class="assets-scroll-view" scroll-into-view="{{bottomId}}" scrollX="true">
                <block wx:for="{{imageList}}" wx:for-item="item" wx:for-index="index" wx:key="index">
                    <view class="{{['assets','_div',index===savedNum&&avatarImage?'active-border':'']}}" id="{{'img'+index}}">
                        <image src="{{item.src}}" data-index="{{index}}" data-src="{{item.src}}"  bindtap="selectAvatarImage" class="_img"></image>
                    </view>
                </block>
            </scroll-view>
        </view>
        <view class="flex justify-around">
        <button class="cu-btn round action-btn" openType="share" id="btn-choose-img"  bindtap="share">分享给朋友</button>
        <button class="cu-btn round action-btn btn-primary" id="btn-save" bindtap="saveCans">保存到相册</button></view>
        <view class="ad-container">
            <view binderror="__e" bindload="__e" unitId="adunit-43f7c4189a8e7c35" class="_div"></view>
        </view>
    </view>
</view>

JS代码:

// pages/main/index.js

Page({

    /**
     * 页面的初始数据
     */
    data: {
        bgImage: "/static/image/bg_image.jpg",
        title: ["快来制作2022新年头像框", "您收到一个好看的头像请注意查收", "您有个新年头像待查收", "2022专属王者头像框"],
        showHeight: 220,
        avatarUrl: "",
        subscribe: true,
        savedNum: 0,
        cansWidth: 280,
        cansHeight: 280,
        avatarImage: "",
        userInfo: '',
        currentFrame: {}, //目前选取的头像框
        frameImage: '', //选中的头像框
        bottomId: null,
        currentCategory: "guoqing",
        categoryList: [{
            id: "guoqing",
            name: "国庆"
        }, {
            id: "years",
            name: "新年"
        }, {
            id: "hot",
            name: "热门",
        }, {
            id: "wangzhe",
            name: "王者",
        }, {
            id: "shengdan",
            name: "圣诞",
        }, {
            id: "wansheng",
            name: "万圣",
        }], //头像分类
        imageList: [],
        assetsList: {
        //头像背景框需要放在远程服务器
            guoqing: [{
                src: "/static/touxiangkuang/guoqing/1.png"
            }, {
                src: "/static/touxiangkuang/guoqing/2.png"
             {
                src: "/static/touxiangkuang/xinnian/93.png"
            }],
        }
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad(options) {
        this.initScreen()
    },

    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady() {

    },

    /**
     * 生命周期函数--监听页面显示
     */
    onShow() {

    },

    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide() {

    },

    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload() {

    },

    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh() {

    },

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom() {

    },

    /**
     * 用户点击右上角分享
     */
    onShareAppMessage() {

    },
    //初始化屏幕
    initScreen() {
        var that = this;
        wx.getSystemInfo({
            success(res) {
                var height = res.windowHeight;
                var showHeight = 220;
                if (height > 900) {
                    showHeight = 340;
                } else if (height > 850) {
                    showHeight = 330;
                } else if (height > 700) {
                    showHeight = 300;
                } else if (height > 600) {
                    showHeight = 240;
                } else {
                    showHeight = 140;
                }
                that.setData({
                    showHeight: showHeight
                })
            }
        });

        this.setData({
            imageList: this.data.assetsList[this.data.currentCategory],
            frameImage: this.data.assetsList[this.data.currentCategory][0].src
        })

    },
    getUserProfile(e) {
        // 推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
        // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
        wx.getUserProfile({
            desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
            success: (res) => {
                //console.log('res:',res);
                this.setData({
                    userInfo: res.userInfo,
                    avatarImage: res.userInfo.avatarUrl
                })
            }
        })
    },
    //切换类型
    imageListTab(e) {
        var categroyId = e.currentTarget.dataset.categroyId
        this.setData({
            currentCategory: categroyId,
            imageList: this.data.assetsList[categroyId],
            savedNum: 0
        })
        this.changeAsset(this.data.assetsList[categroyId], 0);

    },
    //选取头像挂件
    selectAvatarImage(e) {
        var index = e.currentTarget.dataset.index;
        var src = e.currentTarget.dataset.src;
        // console.log('src:',src);
        // console.log('index:',index);
        if (this.data.avatarImage) {
            this.setData({
                savedNum: index,
                currentFrame: src,
                frameImage: src
            })
        } else {
            wx.showToast({
                title: "请先上传图片",
                icon: "none",
                duration: 2000
            });
        }
    },
    // 左右切换
    cutover(e) {
        var type = e.currentTarget.dataset.type
        if (!this.data.avatarImage) {
            wx.showToast({
                title: "请先上传图片",
                icon: "none",
                duration: 2000
            });
            return;
        }

        if (type == 'next') {
            if (this.data.savedNum < this.data.imageList.length - 1) {

                this.setData({
                    savedNum: this.data.savedNum + 1,
                    frameImage: this.data.imageList[this.data.savedNum].src,
                    bottomId: "img" + this.data.savedNum
                })
            } else {
                wx.showToast({
                    title: "已经是最后一张",
                    icon: "none",
                    duration: 2000
                });
            }
        } else {
            if (this.data.savedNum) {
                this.data.savedNum -= 1;
                this.data.currentFrame = this.data.imageList[this.data.savedNum];
                this.data.bottomId = "img" + this.data.savedNum;
            } else {
                wx.showToast({
                    title: "已经是第一张",
                    icon: "none",
                    duration: 2000
                });
            }
        }
    },
    // 选择挂件
    changeAsset(data, index) {
        if (this.data.avatarImage) {
            this.data.savedNum = index;
            this.data.currentFrame = data[index];
        } else {
            wx.showToast({
                title: "请先上传图片",
                icon: "none",
                duration: 2000
            });
        }
    },
    draw() {
        console.log("绘制头像");
        var a = this;

        if (a.avatarImage) {
            var t = wx.createSelectorQuery();
            t.select("#avatar-img").boundingClientRect();
            t.exec(function (t) {
                var r = wx.createCanvasContext("canvas");
                r.clearRect(0, 0, a.cansWidth, a.cansHeight);
                wx.getImageInfo({
                    src: a.avatarImage,
                    success: function success(res) {
                        r.drawImage(res.path, 0, 0, a.cansWidth, a.cansHeight);
                        wx.getImageInfo({
                            src: a.frameImage,
                            success: function success(res) {
                                r.drawImage(res.path, 0, 0, a.cansWidth, a.cansHeight);
                                r.draw();
                                setTimeout(function () {
                                    a.saveCans();
                                }, 100);
                            }
                        });
                    }
                });
            });
        } else {
            wx.showToast({
                title: "请先上传图片",
                icon: "none",
                duration: 2000
            });
        }
    },
    share() {
        wx.showShareMenu({
            withShareTicket: true,
            menus: ["shareAppMessage", "shareTimeline"]
        });
    },
    // 保存到相册
    saveCans() {
        
        // 获取结束
    },
    // 分享到朋友圈
    onShareTimeline() {
        return {
            title: this.title[(0, _random.random)(0, 4)],
            imageUrl: "api/toux/2.jpg",
            path: "/pages/main/index"
        };
    },
    // 页面分享
    onShareAppMessage() {
        return {
            title: this.title[(0, _random.random)(0, 4)],
            imageUrl: "/api/toux/1.jpg",
            path: "/pages/flag/guoqing/main"
        };
    },
    /**
     *  获取相册权限
     */
    wxSaveAuth() {
        return new Promise(function (resolve, reject) {
            wx.getSetting({
                success: function success(res) {
                    if (!res.authSetting['scope.writePhotosAlbum']) {
                        // 如果没有写入权限,则获取写入相册权限
                        wx.authorize({
                            scope: 'scope.writePhotosAlbum',
                            success: function success() {
                                resolve();
                            },
                            fail: function fail(err) {
                                reject(err); // 用户拒绝授权

                                wx.showModal({
                                    content: '检测到您没打开相册权限,是否去设置打开?',
                                    confirmText: '确认',
                                    cancelText: '取消',
                                    success: function success(res) {
                                        if (res.confirm) {
                                            wx.openSetting({
                                                success: function success(res) {}
                                            });
                                        }
                                    }
                                });
                            }
                        });
                    } else {
                        resolve();
                    }
                },
                fail: function fail(e) {
                    reject(e);
                }
            });
        });
    }




})