Css3-animation画动画实战与心得

最近接到一个H5动画的任务,大概状况是这样:

整体动画长度超过10s,这是一个难点,也是唯一的难点。

关于动画的动作拆解和场景分离,先不在这里说,主要说下写大量animation的感受和问题。

总结出的问题:

问题1:为浏览器兼容产生了大量的重复代码;

问题2:连贯动画的执行方案;

问题3:如何保存动画执行后的状态。

 

关于系统限制的几个问题

animation所执行的动画执行后会回到原来的状态;

循环状态的animation在大多数浏览器在重播的时候会有时间差;

变化频率较高的动画会收到机能的限制,出现卡顿;

setTimeout方法的延时在触摸手机的时候会暂停。

 

想到的一些解决方案:

1、既要写animation又要写-webkit-animation(@keyframe也是如此),只是想想就知道一个几秒的动画脚本要写多少重复代码了。

我的解决方案是把动画脚本和普通样式分离,然后先只写webkit的脚本(方便调试),然后再起一个文件单独写通用样式,这样维护一个动画脚本就好了,不用每次修改效果都要改两个地方。(上述操作也可以自行写构建脚本自动化完成,less、sass看情况使用~)

2、经过测试,animation里的infinite属性在replay的时候,并不是无缝的,而是有时差的,而且各浏览器状况不一样,所以想用此属性跟其他元素做组合效果要有准备。

3、因为动画每次执行后都会回到最初的状态,所以我们需要一个方法保存执行后的状态,我的方法是用setTimeout同步动画的时间,在合适的时候加一个心得class来保存元素的当前状态以便在下一个场景中进行新的动画。但是在手机端,手指触摸屏幕会让js暂停运行(wp不会),虽然animation也会暂停,但仍会产生不可以预知的错误,具体解决方案还在研究中。

 

总结:

显然,只要方法得当,animation是完全可以胜任长时间动画的,这让我们摆脱了没有flash,动画实现门槛高的窘境,相反从某些角度,css3写一些动画灵活性更强。

关于小米3安卓4.4ROM浏览器兼容问题

经过一些测试,小米3安卓4.4ROM回有一些不可预计的css和js不兼容问题。

可能是小米的开发在浏览器是做了一些优(wan)化(xiao)。

暂时看比较单行的问题是一个老版本swiper插件的拖拽有问题,更具体的还在测试中。

 

从用户的角度,碰到这种问题,影响了浏览,可以通过对浏览器设置->高级->浏览器标识的调整(应该只要不是默认就可以),来恢复正常浏览。

从开发者,用其他插件类库,或者干脆用自己写的东西,来规避这个问题。

移动端上的点击事件

刚接触手机的时候,前端工程师喜欢用click去处理点击/触摸事件。
渐渐地,通过体验和看过一些文章,我们知道手机上还有touch专用事件,于是我们开始专用touchstart或者touchend来处理触摸事件,然后我们就碰到了各种问题…

Click的延迟问题

click从功能上讲问题不大,但是响应有延迟,传说300毫秒,其实根据机能不同会有更长时间的延迟。

据说一些安卓机用click会出现其他的问题,我没碰到过所以不细说了。

各种touch先天不足

touch响应快,但是你碰到屏幕就是一个touchstart事件,离开屏幕就是一个touchend事件,就算你去拖动屏幕也会执行触发这两个事件,产生的问题我们叫误点击。

解决响应时间和误点击的几个方案

首先我这里不谈jqueryMobile。

那么我知道的几个解决方案为:

fastclick,https://github.com/ftlabs/fastclick;

MBP.fastButton,https://github.com/h5bp/mobile-boilerplate

zepto的tap和singleTap事件,http://zeptojs.com/

上面几个方案都可以很好的解决响应和误点击问题。

那么我们进入正题——“连点”问题

什么是“连点”?
当你点击一个层,而这个层因为事件控制而隐藏了,这时候恰巧这个层下面的区域点击的同一个位置也有点击事件被触发了,那么就是“连点”了。

这个问题发生在弹出层的情况比较多。

上面提到的三个方案在新的手机里面都不太容易(总有特殊情况)出现“连点”问题,但是在老的安卓里面,比如我手上的三星Note中fastclick就会出现连点。

而其他方案表现就很好,所以从这个角度fastclick基本被淘汰了。

还有一种“连点”!

连点还有一种情况,就是你可能在事件里面写了个window.location.href跳转,你这个跳转非常快的完成了,然后又恰巧你跳转的页面在你点击的位置也有个点击事件/链接,那么这个事件/链接也会被触发。
这个是点击问题中最丧心病狂的~
而且关键的是除了click和a标签本身,其他方案都无法避免这个问题。

所以请避免使用点击事件做跳转。

父子Dom的点击事件关系

如果我的一个大dom上有个点击事件,dom中的子dom也有个点击事件,那么点击子dom会执行谁的事件呢?

如果你用click和fastclick就都会执行,其他的方案是执行子dom的事件。

综上所述

如果你在项目中用了zepto,请优先用zepto的相关点击事件,来避免可能发生的问题。
当然了fastclick还有其他的响应功能,如果你需要的话可以在合适的时候去使用它。

iphone和其他平台载入页面时顺序问题

最近在用scrollTop的时候发现的一些问题。

在document.ready中使用scrollTop()获取当前滚屏的值。

假设页面有大于两屏的高度,先把页面拉到中间,然后刷新页面。

其他平台:

先将页面定位到刷新前的位置,然后获得滚动高度。

wap端(iPhone):

先获得滚动高度,再定位到刷新位置。

 

我在做lazyload的时候,因为这个问题iPhone的初始化出现了问题,在载入页面时无法正确的处理当前页面的图片加载。

 

暂时的解决方法有以下集中,

1、加个时间延迟,这样能保证页面跳转后执行初始化,但是要注意,如果你的时间延迟快过你页面构建的速度(ajax之类),还是无法读取到正确的滚屏高度。

2、价格window.scrollTop(0),因为获得高度默认为0,所以让设置他为0也可以达到相对正确的初始化。如果你要在页面加载的时候改变dom结构慎用。

seajs使用时出现的问题累积

加载jquery引用后出现报错

问题:
用正常的方法加载,jquery也确实载入到页面中了,但是引用的时候却说Object not defind。

解决:
引用的id要和jquery里面defind中的值互相对应才可以正常使用。

2.0版本取消了data-config和data-main的属性使用

问题:

解决:
按照常规的方式去引用配置文件和main初始化文件

手机拖动时js停止运行,倒计时实例

问题描述

 

在手机中拖动手机屏幕(window的scroll事件)或关闭手机屏幕时,会让js暂停运行。

这个状况会直接导致类似倒计时这样的效果出现问题。

比如你做了个页面上的倒计时,按照秒的精度倒数,当你拖动屏幕浏览内容时只要你的手没有放开,那时间是不动的。(可以联想到类似轨迹动画也是会停止的)。

 

我的解决办法

一、改变拖动的方式。

将scroll事件改为touchMove,可以让你在拖动的时候仍然保持js的运行。
典型的插件iscroll,虽然这个插件还不是完全体,有一些已知的bug,但是可以给你一个思路让你解决问题。

这个只能解决拖动上得问题,关闭手机屏幕还是无解的。

 

二、利用机器时间差异

这个算是曲线救国(谢谢数学老师),做一个setInterval来循环调用机器时间(间隔事件根据需要设定),如果与上次的调用时间超出预计,那就是产生了拖动和灭屏的状况,那么我们根据这个时间差,来计算目标时间应该达到的目标状态,并重置到这个状态。
我觉得是个代价相对较小的方法。

 

假设刚进入页面的时间是准确的
已知服务器时间 x 和当前机器时间 y
因为服务器时间和机器时间不一定相等
所以我们假定这个时间差z = x-y;
z为恒定值
获取当前机器时间的代码代价较小,我们可以在定时器中一直获取动态的y,再根据z,校准当前的确定的服务器时间,而不用反复请求。
如果是倒计时,需要的是时间差
那就需要一个目标时间a
时间差b的校准公式应该是
b= a-y-z;

 

三、面对鬼畜产品经理

“我要拖动的时候时间是动的,灭屏回来时间也是对的!”
这个时候结合方法一和二,就可以解决了。
我比较懒,方法在上面,自己写一写…
“什么?灭屏回来会卡顿?”
Sorry…

关于input的radio和checkBox组件的一些用法总结

最近用的比较多,在这里总结一下。
要注意的是我下面的东西主要是在移动端开发测试的,chrome也测试了,pc端其他浏览器我会在之后补上说明的。
我这里说的click是已经优化过的点击,自己在合适的时候切换成touch。
另外,无视jquery2+。

大家都知道的

在input外面加上label,或者通过label中的for属性指向input,可以通过点击label区域触发input的change或者focus。
针对radio和checkBox主要就是change事件。
那么触发input:radio和input:checkBox会有什么操作呢?
radio:如果已选中,不会有变化。如果未选中,那么在同一个name里面,选中该radio,原来选中的radio取消选中。
checkBox: 如果已选中,取消选中;如果未选中,改变为选中状态。

你可能不知道的

前提:
这里以jquery的语法描述。
不在html中直接操作checked属性,因为要做遍历。

先说radio:
我们要通过label间接改变一个radio组的状态可以用click事件,也可以用change事件
以$(this).find(“input:radio”).is(‘:checked’)来判断当前的子元素是不是选中状态。
以$(this).find(“input:radio”).get(0).checked = false;来取消选中状态(如果你默认一个都不选中有可能会用到这个)。
click与change的区别就是,不管你该元素的状态是否变化,click都会触发。
而change只有在你元素选中与否变化时才会触发。所以我认为change是优选。
而你想通过其他方式修改这组单选状态的时候,可以通过$(this).find(“input:radio”).eq(index).trigger(“click”)来实现,不能用change。

以上的操作在pc端是没问题的,但是在移动端,想用change操作input的属性是不可以的。
那checkBox呢:
从上面对radio和radio其实没有不同。
但在做特别样式的展示,并且要把丑陋的input隐藏时,要注意保持展示和看不到的input状态是一致的。
我开始用click测试的时候就发现展示状态改变正常,但是input可能没有变化~

总结一些用法

如何确定该选择项目是否被选中:
有人说我要用$(this).attr(“checked”)来查看当前状态,那在我上面说的这个方发现,这么判断永远是空…
用$(this).is(‘:checked’)可以达到判断是否选中。当然你愿意用class标记是否选中也可以。
change和click:
pc端用change提高效率,移动端用click。

综合实例说事

点击查看实例 >>
或者扫码。

一款滚动条插件mCustomScrollbar

考虑到之前自己写的那个功能有欠缺,比如我的只是纵向滚动,这次在自己更新jscroll之余也找到了一个比较完善的插件mCustomScrollbar。

 

mCustomScrollbar

官网:http://manos.malihu.gr/jquery-custom-content-scroller/
github:https://github.com/malihu/malihu-custom-scrollbar-plugin
插件的demo很详细,如果你觉得插件有点大,可以自己优化一下去掉不想要的功能。
注意这类滚动条的插件都要在你的目标元素显示在画布时(能读取到长宽的时候),才能正确渲染,不然你就要自己定宽高了。
我在最近的一个项目中用了它,涉及到一个初始化时内容区域要滚动条从end点开始,并且是横向的。
看代码:
$(".scroll").mCustomScrollbar({
horizontalScroll:true,//横向滚动
scrollButtons:{//是否要左右的箭头按钮
enable:true
},
scrollInertia : 20//滚动的缓动速度
}).mCustomScrollbar("scrollTo","right");//跳到最右

这里注意如果不把scrollInertia设置的低一点,载入的时候会有从左滚到右的动画,最近很懒,就选择了这个比较简单的方案。

一段以userAgent判断是否为手机浏览器的js代码

虽然我不关心,但同事说腾讯是这么用的。
其实就是写了个正则字典穷举手机的可能。个人感觉适用性能覆盖90%以上的用户(只要“安全”浏览器不把userAgent改的太奇葩,或者用户不太奇葩)。
if(/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))){
if(window.location.href.indexOf("?mobile")<0){
try{
if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)){
//移动端
}else if(/iPad/i.test(navigator.userAgent)){
//这里对ipad做了处理
}else{
//移动端
}
}catch(e){}
}
}else{
//pc端
}

wp是个特殊的存在(IE),要怎么单独判断wp呢。
var ISWP = !!(navigator.userAgent.match(/Windows\sPhone/i));
因为wp的特殊性海量的方法给你判断,具体情况再具体分析。