createJs+canvas开发h5+接入公众号踩坑
createJs+canvas开发h5+接入公众号踩坑
CreateJs
使用CreateJs开发h5 ,坑主要分布在预加载,一系列的事件处理,帧处理等几个方面
预加载
在载入页面时,为了防止较大的素材载入慢,一般都采用预加载的方式:
-
preloadJs预加载资源中包括音乐时
//加载音频文件需要调用如下代码行 var preload = new createjs.LoadQueue(true); preload.installPlugin(createjs.Sound);
- 预加载的文件路径
跟html文挡中标签的src赋值相同
音乐播放-soundJs
Android手机直接用soundJs创建AbstractSoundInstance对象就可以直接播放(预加载已经给声音注册过了,只需要调用id就好)
//musicID为预加载中给资源赋予的id
var bgm = createjs.Sound.play("musicID");
当需要暂停声音时
//stop()方法会重置声音的播放进度
bgm.paused=true;
但是在IOS中,由于不允许自动播放声音,我们需要创建一个事件/用户事件去触发,由于我是在微信端打开的网页,所以就用了微信内置浏览器自带的事件
var audio = (function(){
var _audio = new Audio();
_audio.src = './res/1.mp3';
_audio.load();
return _audio;
})()
//我们利用wx的配置事件去触发
wx.config({
// 配置信息, 即使不正确也能使用 wx.ready
debug: false,
appId: '',
timestamp:'',
nonceStr: '',
signature: '',
jsApiList: []
});
wx.ready(function(){
//触发audio对象的play事件
audio.play();
})
当创建完一个播放的音频audio后,就能正常使用soundJs去控制播放其他对象了。
也可以使用其他方式去触发,我只是选择了适合我当时场景的一种。
soundJs创建的AbstractSoundInstance对象的position属性播放时实时变化,指当前音频指针位置,duration属性是指音频总长度,都是以毫秒为单位,两者可以相除计算出音频播放进度。
触摸事件
手机端要想能监听easelJS的一系列点击、按压、拖动等事件,需要设置
createjs.Touch.enable(stage, false, true);
当监听点击事件时,建议用mousedown事件代替,能省去很多麻烦
监听一个图片的点击事件时,只有图片的alpha值大于0才能被触发。
并且如果点击的bitmap对象的区域内没有像素,也是无法触发事件的,所以我们常常用一个alpha为0.01的矩形去覆盖住图片代替监听事件。或者也可以将图片的hitArea指向这个矩形,但被当做hitArea的矩形这时就不能再加入到容器,更新在舞台上。
图片的缩放/旋转-tweenJS
当时工作场景有一个要求是要做出图片的放大,给人走近的感觉
使用tweenJS指定对象的起点属性和终点属性就可以创建出补间动画,创造出平滑的过度效果。但是在类似旋转(修改rotation),缩放(修改scaleX,scaleY)时,需要指定中心点
// 缩放时不仅修改regX,regY,还要修改x,y
// 设置缩放的中心点
container.regX = currentwidth * 0.5;
container.regY = currentheight * 0.75;
container.x = currentwidth * 0.5;
container.y = currentheight * 0.75;
容器的移动
容器被创建时,默认的坐标原点是舞台的左上角。如果此时加入生成的对象,设置xy不会有任何问题。但如果容器因为某些操作被移动,此时容器的坐标原点也发生移动。加入容器的对象的xy仍然是以容器的坐标原点去定位,而不是舞台的原点。如果想根据舞台原点去定位,需要在xy上加上容器的偏移量。
其实就是对象的xy是根据所在容器的原点去定位,而不是舞台。
帧处理
我们舞台的刷新常常放在tick的监听方法handleTicker里。
我们仍需要考虑一种情况,当处理器的刷新速率达不到我们默认设置的60帧时(比如省电模式下的iPhone),场景的刷新情况。
比如在一张长图随着音乐播放进行移动的场景中,如果长图的移动是根据当前音乐持续时间内的舞台刷新次数来移动单位距离的话,当处理器达不到60帧时,会出现图片没有移动完,但音乐已经播放结束的问题(音乐是不会因为刷新率卡顿的)。
所以在有背景音乐,且元素存在移动的场景中,我们需要根据相对时间去定位移动的元素的位置。不能根据这一次刷新,去确定这个元素的位置,而是根据这个时间(上文的position)去判断这个元素应该出现在哪个位置。
Canvas
实现长摁保存图片
img标签在PC浏览器中可以被右键另存为导出为图片,在移动端长摁时则会弹出保存到本地,扫描图中二维码等操作。
当我们用createJS在stage上生成对象,也可以通过长摁canvas标签,此时默认调用canvas的drawToImage()方法,达到img标签的效果。但往往存在多余元素需要剔除,所以就需要我们生成一个透明的canvas标签覆盖在需要长摁的区域内,我们在这个canvas标签内自定义保存的图片内容。
绘制图片
我们往canvas上绘制图像时,需要用到:
ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
第一个参数是img对象,为了防止图片未加载完成就开始绘制我们常常会调用图片的onload()方法进行监听,加载完毕后再进行绘制。
需要注意,对图像的onload事件绑定需要在src赋值前,具体原因百度吧
var img = new Image();
//如果图片跨域,还需要设置跨域
img.onload=function(){
//不要在这里设置跨域,会导致重复触发onload方法
}
img.src="./img/test.png"
剩余的8个参数分别为
sx 可选。开始剪切的 x 坐标位置。
sy 可选。开始剪切的 y 坐标位置。
swidth 可选。被剪切图像的宽度。
sheight 可选。被剪切图像的高度。
x 在画布上放置图像的 x 坐标位置。
y 在画布上放置图像的 y 坐标位置。
width 可选。要使用的图像的宽度。(伸展或缩小图像)
height 可选。要使用的图像的高度。(伸展或缩小图像
绘制文字
当我们需要在canvas上绘制文字时,输入的y坐标为文本的左下角的y坐标,所以需要加上文本自身的大小,否则定位可能会跟预想的出现偏差
ctx.font = "40px Arial";
ctx.fillStyle="black";
var fontWidth= ctx.measureText('1').width;
ctx.fillText(name,283,485+fontWidth);
接入公众号
只做了最简单的网页授权和自定义分享链接,所以这里主要介绍公众号后台的设置,网页授权,wxconfig的配置(实现自定义分享链接)
公众号后台的设置
设置ip白名单(配置wxconfig)
接口权限-网页服务-网页授权-修改 js接口安全域名+域名授权
保存appId和appSecret
网页授权
因为我做的场景是未关注公众号的用户也可以访问,所以采用的是非静默授权的方式:
1.重定向授权页,获取code
2.根据code获取网页授权的accessToken(无限制次数)
3.根据获取的token获取userInfo
参考链接:https://www.cnblogs.com/lovebread/p/5513241.html
实现自定义分享链接
1.根据appId和appSecret获取基础accessToken(有限制次数,所以需要缓存)
同上获取方式类似,只不过需要将获取的token保存在公共变量里
2. 获取JsAPIticket(同上,需要缓存);
3. 生成wxconfig 需要的参数
//wx.config({
//建议开启,可以弹出配置错误
//debug: true,
//appId: '',
//timestamp:'';,
//nonceStr: '',
//signature:'',
//jsApiList: [
//'updateAppMessageShareData',
//'updateTimelineShareData'
//]
//});
// 必填,生成签名的时间戳
String timestamp = Long.toString(System.currentTimeMillis() / 1000);
// 必填,生成签名的随机串
String nonceStr = UUID.randomUUID().toString();
然后就是坑最多的signature:
1.先生成类似url的key=value字符串,key全部小写
String sign = "jsapi_ticket=" + JSAPI_TICKET + "&noncestr=" + nonceStr+ "×tamp=" + timestamp + "&url=" + url;
这里的url是分享页面的url,由于微信会在分享的时候,在当前url后面加上&一系列参数,所以需要从前端传入后端,并且为了防止出现乱码问题,还要将url进行转码
{"url":encodeURIComponent(location.href.split("#")[0])}
后端接收需要解码
java.net.URLDecoder.decode(url,"UTF-8");
然后对构建的字符串进行SHA-1加密
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(sign.getBytes("UTF-8"));
String signature = byteToHex(crypt.digest());
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
这样wxConfig的参数就配置完毕了。
jsApiList: [
'updateAppMessageShareData',
'updateTimelineShareData'
]
这里根据微信的公众号开发的接口文档填写需要配置的接口,然后对接口进行进一步配置
比如我自定义了分享给个人的链接
wx.updateAppMessageShareData({
title: '', // 分享标题
desc: '', // 分享描述
link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: '', // 分享图标
success: function () {
//分享完成后的回调
}
});
其余场景可以去对照微信的公众号开发文档,这里就不多赘述。