校友录取通知书是怎样生成的

近期联合上财学联制作了几个H5,其中有一些收获,也有颇多教训。本文将主要介绍近期校友录取通知书的开发经历,以及接入微信公众平台的经验。

1.项目背景

本次的项目是一个校友录取通知书的H5。虽然我也很不解,这校友难道不是一种自动属性嘛,怎么还要录取了呢。不过既然有需求,淦就完了,奥利给。素材组给了两张图片,第一张作为封面,第二张作为通知书主体,支持用户填写姓名生成图片。并且支持用户分享到朋友圈显示是第几个参与者。


素材1


素材2

2.项目架构

本项目依旧采用我的祖传架构,前端以jq为主,后端采用Thinkphp框架支持。采用了一个移动端滑动页面模板。支持上下滑动,同时引入了intro.js用于进行用户引导。这些技术细节我们将在下面介绍。

3.通知书生成

关于生成图片,我的第一反应是在后端完成,因为上次在前端通过canvas生成长图时,部分iPhone机型发生了文字绘制错位的问题。如下图所示,此处数字绘制有偏差。

然而需求提出在6月21日晚,要求23日晚上线,需求提出距离上线仅有两天时间,22日还和好朋友约好了出去上网(上网误事,大家别学我哈),因而白天不能进行开发,时间很紧。我在后端生成图片不够熟练,因此无奈再次选择了前端canvas绘制的技术路线。

绘制方案是,在该页面首先设计一个用户引导,告知用户使用步骤是

  1. 输入姓名
  2. 保存图片
  3. 分享到朋友圈

在引导结束后,自动弹出键盘,进行上述第一步。由于我希望用户可以在输入中实时获取反馈,就好像直接在图片横线上进行输入一样,因此我设计了一个隐藏的输入框nameInput,并监听其input事件,将文字渲染在画布上。

同时由于canvas在移动端并不支持长按保存,必须转换成img才可以保存,因此还要进行相应的转换。

function drawAdmission(text=''){
//清空画布
    canvas.width = canvas.width;
//绘制通知书底图
    context.drawImage(coverImg2ForDrawing, 0, 0, canvas.width, canvas.height);
//绘制文字
    let originHeight = 844, originWidth = 475;
    context.font = 32 / originWidth * canvas.width + "px testfont";
    if (text.length > 4){
        let line1Num = Math.ceil(text.length / 2);
        let line1text = text.substring(0,line1Num);
        let line2text = text.substring(line1Num);
        let line1Width = context.measureText(line1text).width;
        let line2Width = context.measureText(line2text).width;
        let top1 = 330 / originHeight * canvas.height;
        let left1 = 130 / originWidth * canvas.width +
            (140 / originWidth * canvas.width - line1Width) / 2;
        context.fillText(line1text, left1, top1);
        let top2 = 380 / originHeight * canvas.height;
        let left2 = 130 / originWidth * canvas.width +
            (140 / originWidth * canvas.width - line2Width) / 2;
        context.fillText(line2text, left2, top2);
    } else {
        let textWidth = context.measureText(text).width;
        let top = 380 / originHeight * canvas.height;
        let left = 130 / originWidth * canvas.width +
            (140 / originWidth * canvas.width - textWidth) / 2;
        context.fillText(text, left, top);
    }
//生成图片
    coverImg2.attr("src", canvas.toDataURL("image/png"));
    $("#canvas").hide();
}

nameInput.on("input",function (e) {
    console.log(e);
    let name = nameInput.val();
    if (name.length > 10){
        alert("你的名字太长了喂");
        nameInput.val("");
    }
    drawAdmission(nameInput.val());
});

这样既可实现实时填写生成图片了。

这种方法并非没有缺点,主要缺点就是用户输入和图片生成之间有一定延迟,如果用户手机当前资源占用较多,甚至可能出现顿卡。

4.用户引导

由于上述设计,导致用户在输入过程中没有光标,很容易造成用户误解,从而跳过姓名填写环节,因此需要进行适当的引导。

这里我们使用intro.js实现用户引导功能。intro.js使用非常简单,从官网上下载 introjs.css和intro.js资源文件,引入之后,只要咋页面上选定引导信息的位置就可以了。

<div data-step="1" data-intro="在此处输入您的姓名" id="tip-1" class="tip"></div>
<div data-step="2" data-intro="长按图片保存" id="tip-2" class="tip"></div>
<div data-step="3" data-intro="分享至朋友圈,看看我是第几个领取证书的校友" id="tip-3" class="tip"></div>

如上代码,在页面中通过data-step和data-intro字段设置好步骤顺序和提示文字,再将三个div放置在合适的位置,再通过下面代码代码启动引导即可。

function guide() {
    introJs().setOptions({
        prevLabel: "上一步",
        nextLabel: "下一步",
        skipLabel: "跳过",
        doneLabel: "知道了"
    }).oncomplete(function () {
        //点击跳过按钮后执行的事件
        nameInput.focus();
    }).onexit(function () {
        //点击结束按钮后, 执行的事件
        nameInput.focus();
    }).start();
};

效果如下图所示
在这里插入图片描述

5.接入微信

期初我以为,链接进入微信朋友圈后,会自动以当前标题为朋友圈链接标题,以当前页面icon作为朋友圈链接图标,然而现实却给我浇了一盆冷水。实际上整个项目有近三个小时是解决这个问题,耗费了60%以上的时间。

第一版功能实现后,测试出现了以下问题。

在这里插入图片描述
可以看到,我猜对了一半,分享之后,只有标题,没有图标。后经多方查证,微信对于没有挂靠认证公众号的H5页面,均采用默认灰色图标。因此必须将我们的H5接入一个微信公众号,方可在朋友圈正常显示。

微信要求接入的公众号必须是经过认证的官方号,个人公众号不能提供分享朋友圈功能。好在有学联做后台,还是可以拿到认证公众号的。

下面详细阐述Thinkphp5框架接入微信公众号的技术细节。

1).第一步 设置公众号

在这里插入图片描述
点击此处的开发->基本配置,进入基本配置页面,抄下开发者ID和密码,并修改Ip白名单,将我们服务器ip添加进来,以获取access_token。access_token是微信公众号开发的特殊而必要的机制,具体我们不做展开,只知道要通过服务器获取access_token即可。

需要特别注意的是,微信公众平台并不保存开发者密码,一旦获取需要妥善保管,丢失了很麻烦

然后进入公众号设置的功能设置,在js安全域名这里设置我们的域名。需要注意的事此处仅支持80端口(http)和443端口(https),索性Apache刚好占用80端口,无需额外调整。
在这里插入图片描述

2)第二步 接入ThinkPHP

微信在前端需要通过后台返回的四个参数来进行配置。分别是

参数说明
appId公众号的appId
signature签名
nonceStr随机字符串
timestamp时间戳

这四个参数大致是根据一套基于SHA1加密算法的算法计算出来的。微信在文档中详细介绍了这个算法,并提供了各种语言的示例,可以在下面链接中下载。

http://demo.open.weixin.qq.com/jssdk/sample.zip

我们下载之后,找到PHP文件夹,可以看到四个文件。
在这里插入图片描述
这个sample.php是一个前端模板文件,我们不会用到,我们将剩余的三个文件拷贝下来,房贷ThinkPHP目录下得extend目录中,并适当添加路径。
在这里插入图片描述
然后代开JSSDK.php,在里面添加命名空间org\wechat,并添加变量path,在构造函数中赋值。
在这里插入图片描述
然后修改get_php_file和set_php_file方法,将其中的文件路径加上$this->path参数
在这里插入图片描述

3)编写接口调用JSSDK类
<?php
namespace app\api\controller;

use think\Controller;
use org\wechat\JSSDK;

class Wx extends Controller
{
    public function test()
    {
        $url = input("url");
        $jssdk = new JSSDK("*****APPID*****", "*****APPSECRET*****");
        $signPackage = $jssdk->GetSignPackage($url);
        return [
            "appId" => $signPackage["appId"],
            "nonceStr" => $signPackage["nonceStr"],
            "timestamp" => $signPackage["timestamp"],
            "signature" => $signPackage["signature"]
        ];
    }
}

编写这样的控制器,将我们的APPID和开发者密码填写在构造 方法中,即完成后端接入。注意,在linux机器上可能会出现没有读写文件权限,可以通过对项目目录 chmod 777 -R 暴力解决

4)前端调用wx接口

首先在页面中通过代码引入微信js接口

<script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>

然后进行配置并设置分享朋友圈时的显示信息。

$.ajax({
    type : "get",
    url : "http://sufe100.fgb2019.top/api/wx/test?url="+location.href,
    success : function(data){
        wx.config({
            debug: false,
            appId: data.appId,
            timestamp: data.timestamp,
            nonceStr: data.nonceStr,
            signature: data.signature,
            jsApiList: [
                "updateTimelineShareData"
            ]
        });
        wx.ready(function () {
            console.log("wx ready");
            wx.updateTimelineShareData({
                title: "我是第{$no}个领取校友录取通知书的上财校友,快来点击领取吧!", // 分享标题
                link: 'http://sufe100.fgb2019.top/admission', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                imgUrl: 'http://sufe100.fgb2019.top/static/img/admission/cover-1.png', // 分享图标
                success: function () {
                    console.log("share set success");
                }, error: function(e){
                    console.log(e);
                }
            })
            // var shareData = {
            //     title: '这是是分享标题',
            //     desc: '这是是摘要',
            //     link: url,
            //     imgUrl: 'http://sufe100.fgb2019.top/static/img/admission/cover-1.png'
            // };
            // wx.onMenuShareAppMessage(shareData);//分享给好友
            // wx.onMenuShareTimeline(shareData);//分享到朋友圈
            // wx.onMenuShareQQ(shareData);//分享给手机QQ
            // wx.onMenuShareWeibo(shareData);//分享腾讯微博
            // wx.onMenuShareQZone(shareData);//分享到QQ空间
        });
        wx.error(function(res){
            console.log("wx error!");
            // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
        });
    }
});

其中${no}由PHP后台传入。注意这是微信js 1.4.0版本的写法,早期版本请参考微信文档。

此时,用户分享朋友圈时即可显示预设的图标和文字。

6.项目不足之处

本项目由于开发时间紧迫和开发者能力有限等原因,还存在很多不足。比如再输入时没有光标提示,还有我们希望不要重复记录同一用户访问数量,因此通过ip进行过滤,导致出现了序号相同的问题。
在这里插入图片描述
实际上既然已经接入微信了,可以考虑通过用户openID进行过滤,而放弃第一版使用ip过滤的方案。只可惜时间不过了。

7.鸣谢

感谢上海财经大学学生联合会提供素材和公众号支持
感谢耿士奇同学提供服务器硬件支持

8.项目链接

点击查看原文或扫描二维码。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值