之前有做过一个微信中的H5小项目,其中有一个交互就是点击完按钮,页面由下往上滑动切换至下一页。做完后发现在Android(华为荣耀5a、华为荣耀3c和OPPO A37m)下效果都还好,但在iphone6s(10.2)中测试时却不尽如人意(条件有限,其它机型未测),可谓一波三折。今天就从头到尾做一次总结记录。
一折
先从最简单的demo开始,主要代码如下:
<div id="wrapper" class="wrapper">
<div class="page page-one">
<h1>第一页</h1>
<a href="javascript:void(0);" class="next-btn">下一页</a>
</div>
<div class="hide page page-two">
<h1>第二页</h1>
<a href="javascript:void(0);" class="next-btn">下一页</a>
</div>
<div class="hide page page-three">
<h1>第三页</h1>
<a href="javascript:void(0);" class="next-btn">下一页</a>
</div>
<div class="hide page page-four">
<h1>第四页</h1>
</div>
</div>
html, body, .wrapper {
width: 100%;
height: 100%;
}
.wrapper {
position: relative;
max-width: 640px;
margin: 0 auto;
}
.hide {
display: none;
}
.page {
width: 100%;
height: 100%;
position: absolute;
top: 0;
}
.slideUp {
animation: SlideUp 1s ease;
}
@keyframes SlideUp {
0% { transform: translate3d(0, 100%, 0) }
100% { transform: translate3d(0, 0, 0) }
}
var wrapper = $('#wrapper');
var toNextPage = function(e) {
var curParent = $(e.target).parents('.page');
setTimeout(function(){
curParent.addClass('hide');
}, 1000)
curParent.next().removeClass('hide').addClass('slideUp');
}
wrapper.on('click', '.next-btn', function(e) {
toNextPage(e);
})
上述代码我在三个安卓机上测试时都没有问题,但在iOS下却有这样的一个异常,如果用户不小心点击在事件委托的元素"div.wrapper"上而非按钮区域,再点击"下一页"按钮时,下一页就会直接显示出来,而没有从下到上的滑动效果。。
针对这个异常,我也查找了好久原因,很遗憾,,至今没能找到导致这个异常的原因,但找到了两个解决方案:
- 不采取事件委托,将点击事件直接绑定到a标签上。
- 引入fastclick库。
修复之后的效果如下:
当引入fastclick解决异常后,我猜想,这个异常会不会是由iOS本身的原生点击事件导致的?如果您知道原因,希望不吝指教,先谢过了!
二折
在解决了上述问题后,接下来为了让按钮看着漂亮一些,我给每一页的翻页a标签加上背景图并去掉文本内容:
<a href="javascript:void(0);" class="next-btn"></a>
.next-btn {
position: absolute;
bottom: 20px;
left: 50%;
margin-left: -80px;
width: 160px;
height: 60px;
text-align: center;
background: url(./../images/btn-start.png) no-repeat;
background-size: contain;
}
这样改动后,Android下仍没有问题,但iOS下又出现了类似的异常:这次是直接点击按钮后,下一页就会直接显现出来而没有滑动效果。。
在尝试各种解决方法后,无意中发现,在给a标签添加active选择器后,滑动效果正常,而且a标签的交互视觉效果似乎也更好了点。。什么鬼,问题是因此而解决了,但同上,原因还是不明,研究中……
.next-btn:active {
background-image: url(./../images/btn-start-a.png);
}
效果如下:
三折
页面总算可以一页一页地顺利切换了,下面需要做的是一个转盘抽奖,这里只展示简化部分。
// html
<div class="turntable">

<div class="lottery_btn">开始抽奖</div>
<div class="pointer"></div>
</div>
// css
.turntable .pointer {
...
-webkit-transition: -webkit-transform 2s ease-out;
transition: transform 2s ease-out;
...
}
// js
wrapper.on('click', '.next-btn', function(e) {
toNextPage(e)
}).on('click', '.lottery_btn', function(e) {
var rotate = 'rotate3d(0, 0, 1, ' + (360*4+45) + 'deg)';
$('.pointer').css({
'-webkit-transform': rotate,
'transform': rotate
})
// 由于我上面设置的rotate过渡时间是2秒,所以在此处写的是2.2秒后进入抽奖结果页。
setTimeout(function() {
toNextPage(e)
}, 2200)
})
首先我的想法很简单,就是让转盘的指针根据结果在两秒内转动四圈以上最终落在奖品上,与此同时,抽奖结果页再紧接着滑动出来。但结果却还是出乎意料:
转盘指针确实可以正常落在奖品上,但在iOS下只转动了不到半圈。
既然问题出在了转动上,首先想到是不是需要给转动指针的父元素div.turntable添加transform-style以及perspective等属性,但发现添加后还是同样的效果。再联想到可能是rotate3d方法的支持性问题,于是换做rotateZ方法,转动正常。。也就是只做了下面的变动:
var rotate = 'rotateZ(' + degree + 'deg)';
当转盘指针刚停止滚动的时候,在iOS下抽奖结果页直接显现出来,和一二折中遇见的情况很是相似。。
从上面的代码可以看出,我其实是想用setTimeout控制指针旋转动画结束后的下一步动作,问题其实也是出在了这个里面。说白了,如果有一个可以监听动画结束的事件,而将下一步操作放在该事件处理程序中岂不OK?果不其然,当通过监听transitionend事件来处理后,一切正常……
$('.pointer').css({
'-webkit-transform': rotate,
'transform': rotate
}).on('transitionend', function() {
toNextPage(e)
});
小结
其实上面写了这么多,总结起来无非这两个问题:
- 在iOS下使用transform: rotate3d()制作旋转动画效果时,iOS会以最快捷的路径从起始角度旋转至终止角度,因此旋转角度不会超过180deg。所以如果要连续平滑的从起始角度过渡到终止角度,建议使用rotateX()、rotateY()和rotateZ()代替。
- 某些情况下(应该不限于上面三种情况),在iOS中将一个元素的display属性从none设置为block后,紧接着为其添加基于transition 和 translate 的动画效果时,动画效果失效。失效原因暂不明确。。继续研究中。
能力和条件有限,总结和测试或许都有很大不足!这是demo地址 ,如果您有什么想法,希望不吝赐教!
最后附上完整效果图: