问题:在使用了iScroll4的容器内,当表单元素focus聚焦后键盘出现时,可能会存在iScroll区域高度不更新,滚动异常问题;而且当前聚焦的表单元素可能不出现在可视区域内,影响用户体验。
iKeyboardScroll4就是这么一个解决方案
Github见:https://github.com/zawaliang/iKeyboardScroll4
如今大多数机型都支持onorientationchange事件,iScroll4在不支持onorientationchange事件的机型中使用onresize事件来对滚动区域进行自动刷新操作。所以上面说的表单情况,在大多数机型里都会存在高度不刷新的情况。
1 |
RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize' , |
那么现在的问题就是检测键盘出现与否,然后调用refresh接口刷新滚动区域高度。由于没有相应的接口来检测键盘状态,所以我们通过onresize来检测窗口高度变化,配合当前元素的聚焦状态来模拟键盘状态。同时需要考虑在键盘出现时翻屏的情况。
以下为核心函数,用于检测键盘状态:
3 |
if (_landscape != _landscape2) { |
6 |
var tmpWidth = _initWinWidth; |
7 |
_initWinWidth = _initWinHeight; |
8 |
_initWinHeight = tmpWidth; |
10 |
_initWinWidth = $(window).width(); |
11 |
_initWinHeight = $(window).height(); |
15 |
var h = $(window).height(); |
16 |
_display = _activeElement !== null && _initWinHeight > h; |
18 |
$.each(_callback, function (k, v) { |
19 |
v.apply( null , [_display, _activeElement]); |
21 |
_landscape = _landscape2; |
由于不确定orientationchange与onresize哪个先触发,并且实测发现iOS下orientationchange比onresize迟触发,造成翻屏状态的获取不好捕获,所以针对IOS系统,当翻屏时我们使用orientationchange来检测,其他状态下使用onresize。翻屏状态下,Android下orientationchange之后获取高度存在时间差,所以需要onresize后延时获取进行处理。
1 |
$(window).on( 'orientationchange' , function (e) { |
2 |
_landscape2 = !!(window.orientation & 2); |
6 |
}).on( 'resize' , function (e) { |
12 |
&& (_landscape != _landscape2 |
13 |
|| $(window).width() != _initWinWidth)) { |
17 |
_timer && clearTimeout(_timer); |
19 |
_timer = setTimeout(detect, 200); |
当存在聚焦元素,且窗口高度比初始化时的窗口高度小时,即认为键盘出现了。
1 |
_display = _activeElement !== null && _initWinHeight > h; |
键盘的问题解决了,我们需要解决聚焦元素的位置问题,否则可能会出现聚焦元素不在可视区域的情况,用户茫然不知当前输入的是啥。需要注意的是在iOS6下,系统会自动定位到聚焦的元素,但升级后的iOS7,受iScroll影响,造成输入框focus聚焦失败; iOS5.x 6.x下不存在这个问题,具体原因待研究(这里有篇文章不错,可以看下:《运用webkit绘制渲染页面原理解决iscroll4闪动的问题》),所以iOS7下的表现跟Android比较类似,所以我们只对非iOS6以及iOS7的做处理即可。
4 |
if ((!$.os.ios || _ios7) |
5 |
&& display && focusElement) { |
6 |
offset = $.type(offset) == 'number' ? offset : 5; |
8 |
var el = $(focusElement), |
9 |
winHeight = $(window).height(), |
10 |
top = el.height() + el.offset().top + offset; |
13 |
if (top - iScrollInstance.y > winHeight) { |
14 |
iScrollInstance.scrollTo(0, winHeight - top + iScrollInstance.y, 0); |
18 |
_ios7 && focusElement.focus(); |
说到iOS7,还有一个地方比较怪异,当点击输入框,键盘会出现,但是输入框没有聚焦。需要手动再点击一次。初步排查是iScroll4的问题,但没搞懂是哪出问题了,所以iKeyboardScroll4里对这些情况做了处理,暂时解决了这一问题。
移动侧WebApp坑还是比较多,需要不断的积累经验才行啊~