近期联合上财学联制作了几个H5,其中有一些收获,也有颇多教训。本文将主要介绍近期校友录取通知书的开发经历,以及接入微信公众平台的经验。
1.项目背景
本次的项目是一个校友录取通知书的H5。虽然我也很不解,这校友难道不是一种自动属性嘛,怎么还要录取了呢。不过既然有需求,淦就完了,奥利给。素材组给了两张图片,第一张作为封面,第二张作为通知书主体,支持用户填写姓名生成图片。并且支持用户分享到朋友圈显示是第几个参与者。
素材1
素材2
2.项目架构
本项目依旧采用我的祖传架构,前端以jq为主,后端采用Thinkphp框架支持。采用了一个移动端滑动页面模板。支持上下滑动,同时引入了intro.js用于进行用户引导。这些技术细节我们将在下面介绍。
3.通知书生成
关于生成图片,我的第一反应是在后端完成,因为上次在前端通过canvas生成长图时,部分iPhone机型发生了文字绘制错位的问题。如下图所示,此处数字绘制有偏差。
然而需求提出在6月21日晚,要求23日晚上线,需求提出距离上线仅有两天时间,22日还和好朋友约好了出去上网(上网误事,大家别学我哈),因而白天不能进行开发,时间很紧。我在后端生成图片不够熟练,因此无奈再次选择了前端canvas绘制的技术路线。
绘制方案是,在该页面首先设计一个用户引导,告知用户使用步骤是
- 输入姓名
- 保存图片
- 分享到朋友圈
在引导结束后,自动弹出键盘,进行上述第一步。由于我希望用户可以在输入中实时获取反馈,就好像直接在图片横线上进行输入一样,因此我设计了一个隐藏的输入框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.项目链接
点击查看原文或扫描二维码。