背景
最近做了一个公众号H5的动画分享活动,虽然做之前已经意识到肯定有不少坑,最终完成到上线的跌宕起伏程度还是超出了我的预期。 下面是我总结了从开发到上线中间的坑,希望能给大家做类似项目时候一些意见建议。
技术栈:vue + vue-router + velocity.js
webpack局域网访问
开发过程中,因为需要频繁测试和调试样式,所以想用电脑启动本地服务,手机(和电脑连接同一个wifi)访问本地服务方便调试,webpack文档中介绍 配置
host:0.0.0.0
按照这个配置后,重启本地服务,仍然无法访问电脑启动的服务,捣鼓了很久,最终发现是windows 10 的防火墙策略
公用网络的防火墙策略需要关闭。
页面布局
一般这种全屏动画项目是不允许出现滚动条的,所以为了适配各种屏幕及机型,必须要做一个最小高度安全区,保证在这个安全区的内容是能满足绝大部分机型的(一般是以iphone6为基准)
- 上图中浅蓝色区域即为安全内容区,页面的可交互内容及动画元素建议都基于此区域定位。
- 内容区需要基于屏幕高度垂直居中, 方便适配各种机型。
- 图中安全区高度554 为啥不是603,是因为微信ios版本在有历史访问记录的情况下会新增一个白底导航条,导航条高度49px 导致页面的安全高度区域减少了49px,而且只要微信做了公众号授权登录是一定会有这个导航条的,所以这个空间必须要算进去。
transition 和 animation 适用时机
每个页面中都有一些转场动画和点缀动画,这里就面临一个动画的实现方式选择问题,transiton和animation都能实现的效果,究竟选择哪种实现方式: 实加开发中发现 animition动画会在元素ready以后自动开始,transition很难做到(需要使用js辅助),所以自然加载触发的动画比较适合animation,交互触发的则无特别大区别。
开源库坑:
活动页面中存在了大量的连续性队列动画(A ----> 动画结束 ---- B ----> 动画开始),如果全部都用vue的原生事件绑定来完成的话,成本太高,需要在各个动画元素上绑定事件处理函数,而且开发体验特别不友好。 之前了解过velocity.js 做动画队列很不错所以就引了进来。 刚开始测试一些动画都非常顺利。 直到提测以后发现,有些页面的动画卡住了。 添加调试信息后发现页面报错了:
然而这个错误看的让人完全懵逼。
初步怀疑是开源库文档和代码不同步的问题,我使用的是2.0.6版本,文档还是1.5版本,查了新版本的相关资料,了解到 transform变换需要添加 初始值和结束值参数,不能像其他动画变换属性一样直接使用结束值自然变换。
举个例子
变换透明度
Velocity($el, {
opacity:1
}, {
duration:1000
});
transform变换
Velocity($el, {
transform:["translateY(-8rem)', 'translateY(0)"] //注意数组的顺序是 终点 - 起点 有点反直觉
}, {
duration:1000
});
按照上述方案改了以后,用自己手机测试正常(安卓,此处有伏笔),以为结束。 ps:
- velocity.js 的官方文档跟2.0版本差别较大,文档上只是说新增了添加初始变化的值,实际测试发现transform一定要有初始值,否则就会报错;
- 另外2.0以上版本也不再支持文档上出现的
这种简写在2.0版本上都是不支持的,必须使用原生transform。
上面提到安卓实测正常,结果测试同学用ios测试,GG还是不动,不过页面也没有报错信息了(感觉更绝望,还不如有报错信息呢) 没办法只能继续调试,还好项目装了调试工具eruda。 最终通过拉长动画时间,观察dom节点,发现目标动画元素的style根本没有变化,反而是dom属性新增了一个 transform在变化。 问题终于找到了(心累),在iOS设备上,transform变化被应用到attribute 上而非style上。 虽然找到了问题,但是不知道咋个改,捉急,只能跑去github上看看开源库是怎么写的,最终找到了这段代码
var base = document.createElement('div'),
rxSubtype = /^SVG(.*)Element$/,
rxElement = /Element$/;
Object.getOwnPropertyNames(window).forEach(function (property) {
var subtype = rxSubtype.exec(property);
if (subtype && subtype[1] !== 'SVG') {
// Don't do SVGSVGElement.
try {
var element = subtype[1] ? document.createElementNS('http://www.w3.org/2000/svg', (subtype[1] || 'svg').toLowerCase()) : document.createElement('svg');
// tslint:disable-next-line:forin
for (var attribute in element) {
// Although this isn't a tween without prototypes, we do
// want to get hold of all attributes and not just own ones.
var value = element[attribute];
if (isString(attribute) && !(attribute[0] === 'o' && attribute[1] === 'n') && attribute !== attribute.toUpperCase() && !rxElement.test(attribute) && !(attribute in base) && !isFunction(value)) {
// TODO: Should this all be set on the generic SVGElement, it would save space and time, but not as powerful
registerNormalization([property, attribute, getAttribute(attribute)]);
}
}
} catch (e) {
console.error('VelocityJS: Error when trying to identify SVG attributes on ' + property + '.', e);
}
}
});
这段逻辑是把svg元素添加变化函数,使用属性变换,但是不知道为啥,在ios上被应用到普通元素上了,最终把这段逻辑注释掉(因为我的页面也没有svg元素),ios也正常了,不过我仍然没找到具体到底是哪里条件判断出了问题,导致这个应用错误的(主要是里面使用了很多js位运算,看的我脑壳疼,不想看了),不过还是去给作者提了个issue,看看他会不会确认这个问题了。
微信jssdk & vue-router history模式混合坑
因为想用transition组件提供的页面转场动画能力,所以我当时是做了十几个page.vue,(坑的伏笔)
- ios环境,申请了jssdk以后,发现未生效,调试发现因为前面几个页面是自动跳转的,导致jssdk无法设置成功,改造成jssdk初始化成功以后再跳转。(已避开ios申请jssdk权限必须使用首次进入url来申请的坑)
- ios正常以后,测了两个安卓机也正常了(小米和华为),以为解决问题----下午测试同学反馈oppo和有一部华为自定义分享未成功, 最终测试发现,安卓微信对待history模式使用自定义分享jssdk功能再不同机型上表现有差异,部分手机支持在入口页设置即可(小米),部分手机又要求(华为和oppo)每个页面都要重新申请。最终实测,每个页面都重新发起申请,安卓手机都支持,顺势改为每次进入页面都重新设置分享内容。
- 每次页面都注册会导致ios每个页面都需要等待jssdk初始化成功以后才能继续跳转,最终折中的方案是,ios只在入口页设置jssdk,安卓每个页面都设置。
- 本以为就此结束,结果发现,ios自定义的分享内容 标题,小标题,图片都没问题,但是链接却不是我设置的链接(活动入口页,有一堆中转页逻辑),而是当前页面的链接,为了修改这个问题我甚至修改了引入的微信jssdk的代码,把参数url写死为目标页面地址--------无效。无法改变微信的行为,就只能改变自己了!! 路由和页面做如下逻辑处理:
home即为活动入口页 添加标识
export default {
beforeCreate() {
window.entryFlag = true;
}
};
在路由中新增代码
router.beforeEach((to, from, next) => {
if (to.name !== 'home' && !window.entryFlag ) next({ name: 'home' });
else next();
});
无论从哪个页面进来只要没有entryFlag的标识,都会被路由导航到home页重新开始,解决问题 ps: 一定要使用 beforeEach,不能使用afterEach,此时路由已经生成,会影响jssdk的注册
图片格式
页面中间有些小动画,最开始是用gif做的,但是设计师同学觉得gif的白边问题不可接受,重新切雪碧图又工作量比较大,设计同学建议用apng,本来我以为apng会有兼容性问题,但是最终实测,发现ios 和 安卓都支持,遂把gif改为apng。 apng最终到处的图片格式后缀还是.png,所以我有了个大胆的想法,做成雪碧图,减少并发请求。然而做成雪碧图以后,发现失去了动画效果。 开始以为是合成雪碧图的时候丢失了动画信息,所以尝试用原本的apng图片直接切换成背景图看看效果如何,结果也不动了。改成img标签 以切正常。 总结: apng图片目前ios和安卓支持都没问题,但是只能作为前景图 img标签引用,不能用背景图,否则会失去动画效果,所以也就没法做成雪碧图了。
ios音乐的坑
虽然ios不支持音乐自动播放,但是在微信浏览器环境有一个时机可以触发一次音乐播放
document.addEventListener('WeixinJSBridgeReady', () => {
document.getElementById('music1').play();
});
然而本来页面是有两个音乐的,一个前景声,一个背景声,ios环境下只能把前景声和背景声合并成一个声源(还要注意声音是进入页面就播放才行,如果是要做到音画同步,就不想要要有交互,不能自动播放)。 ps:安卓是支持多个audio标签自动播放的, 无限制。
ios识别小程序码和二维码的坑
ios环境 vue-rotuer history模式下,页面有自动跳转行为,会导致跳转结束后的页面上的小程序或者二维码无法唤起长按识别的功能, 尝试了社区各种解决方案:
- 二维码大小问题 ---- 大小改大(无效)
- blog.souche.com/ios-wei-xin… ---- 他写的demo有效,但是对我的项目无效,并且还把jssdk分享整坏了。
- 改成hash模式 ---- 解决问题 最终选择改成hash模式解决这个问题,本来以为会成本很高,后来发现history模式改造成hash模式成本并不高,因为nginx设置的问题,之前的链接都可以继续使用 同时改为hash模式以后还解决了前面 history模式各平台的jssdk分享问题,不再需要区分平台初始化,分享链接也是正确的。
总之,hash模式虽然不好看,但是微信的支持还不错,history模式微信的的支持实在是不忍直视!
上面就是我此次项目的踩坑记录,总结下比较关键的几个点:
- 页面设计需要提前规划内容安全区,方便后续做页面兼容
- 元素加载后自动触发动画 用animation比较合适。
- Velocityjs 在ios上关于transform变化有坑,需要注意
- vue-router history模式下的jssdk分享神坑,建议交互跳转(比如点击)自动跳转需要等初始化完成,安卓需要每个页面都初始化。
- apng图片需要作为前景图才能有动画效果,背景图不行。
- ios上不建议设置自动播放音乐,最好提前沟通预留交互触发
- history模式下,自动跳转会导致ios失去识别小程序码和二维码的能力,慎重考虑。
- history模式切换hash模式成本不高