彻底解决IOS HTML页面上光标跳行、光标不跟随页面问题


 

继:修复IOS上滑动HTML界面光标乱跳

声明:这里只是说明一种处理方法

继上一篇文章,处理IOS滑动时,光标不跟随页面滚动,处理方法是,监听touchmove事件,获取当focus的元素,使之失去光标;但是这种方法并不能真正的解决问题,比如,你进入页面,并不滑动页面,而是去点击屏幕可见区域最底下的输入框时,问题就出来了,如图:

这里说一下,网络上大多说是IOS上fixed定位,修改定位为absolute;或者是添加fastclick.js库,加速手机上tap事件的响应;

问题就出在这里,你确定你的页面是定位的因素?你确定添加了fastclick库就可以了?如果尝试了上面两种方法还不行,你可以接着往下看;

仔细观察页面,当你点击最后一行输入框时、滑动页面时,或者是弹框;你可以看到页面上的活动元素先聚焦再滚动;也就是说,activate元素的聚焦事件在页面滚动之前或者滚动完成之前就已经完成了,所以这时候页面滚动,而光标又不跟随滚动,就造成了光标跳行、错乱的问题。

解决方法:

一、输入框在聚焦的时候,会弹起软键盘;所以,我们监听软键盘弹起事件,在弹起事件后,进行dom重绘,但是这种必须要加延时,代码如下:

            document.body.addEventListener('focusin', function () {  //软键盘弹起事件
                var node = document.activeElement; //当前focus的dom元素
                setTimeout(function () {
                    if (node) {
                        if (node.nodeName == "TEXTAREA" || node.nodeName == 'INPUT') { //如果是input或textarea
                            if (node.style.textShadow === '') {
                                node.style.textShadow = 'rgba(0,0,0,0) 0 0 0'; //改变某个不可见样式,触发dom重绘
                            } else {
                                node.style.textShadow = '';
                            }
                        }
                    }
                }, 1000);
            });

二、监听屏幕滚动事件;是屏幕滚动,不是手指滑动的事件,因为我这里使用的是sencha Touch移动端框架,所以,可能会不适应,但是道理是一样的;代码如下:

initialize: function () {
        var me = this;
        me.callParent();

        me.element.on({
            submit: 'onSubmit',
            scope: me
        });

        var scrollable = this.getInitialConfig().scrollable;
        if (scrollable == null || scrollable == false) {
            this.isScrollable = false;
        } else {
            this.isScrollable = true;
        }
        //添加scroll事件监听
        me.getScrollable().getScroller().on({
            scroll: 'onScroll',
            scope: me
        });
    },
    //添加scroll事件响应函数
    onScroll: function () {
        var node = document.activeElement; //当前focus的dom元素
        if (node) {
            if (node.nodeName == "TEXTAREA" || node.nodeName == 'INPUT') { //如果是input或textarea
                if (node.style.textShadow === '') {
                    node.style.textShadow = 'rgba(0,0,0,0) 0 0 0'; //改变某个不可见样式,触发dom重绘
                } else {
                    node.style.textShadow = '';
                }
            }
        }
    },

这里是修改sencha Touch formpanel容器的源码,添加了事件的监听

对于第二个方法,如果你使用的是其他的框架,同样的你需要做一些修改。但是道理是一样的

三、理论,未实现;同样是监听屏幕滚动事件,使用定时器,实时监听该页面scrollTop,如果scrollTop在改变,那么就说明页面在滚动,如果在滚动,就获取当前页面activate元素,使之重绘

最后说一下,为什么不能监听touchmove事件,因为我们在滑动屏幕时,并不是手指离开了屏幕,屏幕就停止滚动了,屏幕还会有一个关心滚动存在;所以,单单是监听touchmove并不能解决光标错乱、跳行问题。除非,当你手指离开时,屏幕立马停止滚动。所以还是监听屏幕滚动最为靠谱

补充:如果你在touchmove中处理了光标不跟随,也就是move时取消光标聚焦;这里你可以将touchmove注释掉,因为监听scroll处理后,光标便会跟随页面滚动