• 移动端踩坑之旅-IOS下FIXED、软键盘相关问题总结


    最近一个项目掉进了移动端的大坑,包括ios下fixed布局,h5唤起键盘等问题,作为一个B端程序员,弱项就是浏览器的兼容性和移动端的适配(毕竟我们可以要求使用chrome),还好这次让我学习了一下相关知识。让我们一起来看一下我怎么挣扎出这个大坑的。

      一、背景

          先看一下要做什么,也就是一个文章评论的版块,下面依次有输入框,点赞,收藏等 。大概长下面这个样子:  

          要求也很常规,吸底,输入评论提交。那么上来就输代码吧。

      二、ios下fixed布局

           关于这种吸底操作,上来就直接选用fixed了,这种场景舍他其谁。初步的布局就是这个样子了。(因为我是用的react,jsx的写法粘贴上来简直让人崩溃,就随手写一段代码代表下,勿怪)

    1 <body>
    2     <div class='top'></div>
    3     <div class='main'></div>
    4     <div class="fix-bottom"></div>
    5 </body>

    然后css就不多写了,浏览器上一看还挺想那么回事。然后在ios上就出现了点意外情况。就成了这个样子(希望没有我厂的工友)

    就这样被顶起来了。。。。出现问题就算当时要快速解决没有时间去深究,那么下来也要去搞清楚因果,毕竟我们不是为了解决问题而解决问题。一起看下原因

      2.1   ios下fixed失效的原因

      软键盘唤起后,页面的 fixed 元素将失效(ios认为用户更希望的是元素随着滚动而移动,也就是变成了 absolute 定位),既然变成了absolute,所以当页面超过一屏且滚动时,失效的 fixed 元素就会跟随滚动了。

    不仅限于 type=text 的输入框,凡是软键盘(比如时间日期选择、select 选择等等)被唤起,都会遇到同样地问题。

      2.2 如何解决

      既然ios就是这个样子,我们只能选择接受现状,只能想办法绕过去了。大致说来两个方向:

      1、既然会变成absolute,索性直接使用absolute算了,

      bottom直接以body作为父元素来进行绝对定位,不过这种网上都不推荐,想来有更多的问题等待修正,前人的经验还是要借鉴的,所以我也没有去尝试,有兴趣的同学可以尝试一下。

      2、不让页面滚动,而是让主体部分自己滚动

      如果fixed的失效,但是页面并没有超过一屏的长度,那么无论absolut或者fixed也没什么差别。顺着这个思路我们回顾一下上面的结构,完全可以让main直接滚着玩就行了。将吸底的元素和主题作为两大容器,主体部分,设置绝对定位,固定在屏幕中间,超出部分就自行滚动,吸底元素就可以自己玩了

    大概就是下面这个样子:

    复制代码
    1 <body>
    2     <div class='warper'>
    3         <div class='top'></div>
    4         <div class='main'></div>
    5     <div>
    6     <div class="fix-bottom"></div>
    7 </body>
    复制代码

    对应样式如下:

    复制代码
     1 .cont-warper{
     2     position: absolute;
     3      100%;
     4     left: 0;
     5     right: 0;
     6     top: 0;
     7     bottom: 0;
     8     overflow-y: scroll;
     9     -webkit-overflow-scrolling: touch;/* 解决ios滑动不流畅问题 */
    10 }
    11 .fix-bottom{
    12     position:fixed;
    13     bottom:0;
    14      100%;
    15 }
    复制代码

     这样就能避免上面那个问题了。但是ios下,对于吸底元素而言在屏幕下半部分唤起键盘的时候,会被遮住部分东西,有的资料提到是第三方输入法的toolbar,我看到的现象是吸底元素被遮住了,对于这种情况,我们只好加个监听事件,当唤起键盘的时候,设置scrollTop值,也就是说你不上来,我强迫你上来:

    复制代码
    /**
         * 唤起键盘,滚动
         */
        scrollContent() {
            this.interval = setInterval(() => {
                this.scrollToEnd();
            }, 500)
        }
        scrollToEnd() {
            document.body.scrollTop = document.body.scrollHeight;
        }
        clearSrcoll() {
            clearInterval(this.interval);
        }
    复制代码

    设置延时切换,input当失去焦点的时候清除。 

       三、h5调用虚拟键盘

      解决了布局问题,下面就开始happy的写功能吧,开始之前,让我们回头继续看下上面的视觉图,是不是感觉少了点什么。我们的提交button呢?一般来说是这样:

      这让我如何下手,还好请教了下老大,作为一个老司机他轻轻的告诉我三个字:网上搜。。。。。

      不扯淡了言归正传,对于这种显然是要利用软键盘上的回车来提交信息的。你最常见的一定是搜索按钮,就是type=‘search’的使用。如果想通过键盘来提交信息,就要把form表单拉出来用用了。

      3.1   键盘提交事件

      一般来说是这样做的,将input包括在form表单内,这样就可以监听submit事件了。如果有人问我是走的ajax不是form表单的话,请记得有个onSubmit事件可以来做一些你想做的事情。代码如下:

    1 <form onClick={::this.changeInput} onSubmit={this.comment.bind(this, postID)}>
    2 <Input type="text" placeholder="请输入" id='commentInput'  value={::this.getVal()} onFocus={::this.scrollContent} onBlur={::this.clearSrcoll}/>
    3 </form>

    可能看起来比较蛋疼,没办法react的jsx就是这么蛋疼。上面的那么多事件还真的都有必要。思路如下:

      1、submit事件可以监听到用户软键盘的回车键,对于ajax提交,这里需要我们阻止下form的默认事件,避免form提交的刷新页面的行为

    1  comment(postID, e) {
    2         e.preventDefault()
    3         // 阻止多次提交
    4         // 你的代码
    5 
    6     }

      这样,监听软键盘的提交事件就完成了,但是其他问题又来了  

      3.2  其他区域唤起软键盘

      再看一眼视觉图,不仅仅是点击input可以提交评论,还有一种回复别人评论的需求,点击回复的label也需要唤起键盘来进行操作。

      

          移动端而言对于h5的input,focus和blur可以唤起和收起键盘,这样顺理成章的我们可能这样做。给每个回复绑定个事件,点击的时候让input获取焦点即可,代码如下

      

    复制代码
     1 <div className="comment-resquetion" onClick={this.changeParent.bind(this, comment.comment)}>
     2 回复
     3 </div>
     4 //input获取焦点,并现实被回复人昵称
     5 changeparentComment(val) {
     6         let commentInput = document.querySelector('#commentInput')
     7         commentInput.focus()
     8         this.setState({
     9             parentComment: val
    10         })
    11     }
    复制代码

          这样在android下面是可以的,在ios下面又遇到了问题,非input触发的事件是不能唤起键盘的,这样和window.open的限制差不多,只有用户主动的操作才会允许唤起键盘,所以这样是不可以的。

      针对这种情况,我们可以投机取巧一下,既然必须要是input触发的操作,那么回复那里我直接用一个透明的input置于上方不就可以了。

      

    1 <div className="comment-resquetion" onClick={this.changeParent.bind(this, comment.comment)}>回复<input type='text' className='hide-input'/></div>

      css样式如下:

    复制代码
    .comment-resquetion{
        position: relative;
        font-size: 0.28rem;
        color: #3E93C2;
        letter-spacing: -1px;
        line-height: 0.45rem;
        padding: 0.05rem  0 0.15rem 0.32rem; 
    
    }
    .hide-input{
        position: absolute;
         100%;
        height: 0.28rem;
        opacity: 0;
        z-index: 1000;
        left: 0.32rem;
        top: 0;
    }
    复制代码

    当点击回复的时候,其实点击的是input,这样就能避开限制唤起软键盘了。

       3.3 关闭键盘

       到这里,以为就这样结束了,结果发现还有个问题,当点击软键盘提交完成的时候,键盘并不能隐藏,这让人有点尴尬,因为点击提交按钮之后,没有主动收起键盘。因为当在软键盘上操作是,io用户的输入行为还在继续,所以不会收起键盘,如果是点击旁边的button提交,就会自动收起了。既然不能主动收起,只能我们手动强制了,在提交事件返回后,可以手动将焦点移除,这里最好做个延时,不然体验有点太快。

    1 this.commentInput = document.querySelector('#commentInput')
    2   setTimeout(() => {
    3               this.commentInput.blur()
    4               // 评论成功都置空
    5              this.props.changeParent(null)
    6    }, 500)

      到这里这个看起来很小的功能终于结束了,有必要做个总结以供自己及有需要的同学做个参考。

    参考文章:

    http://efe.baidu.com/blog/mobile-fixed-layout/   

  • 相关阅读:
    CodeForces 659F Polycarp and Hay
    CodeForces 713C Sonya and Problem Wihtout a Legend
    CodeForces 712D Memory and Scores
    CodeForces 689E Mike and Geometry Problem
    CodeForces 675D Tree Construction
    CodeForces 671A Recycling Bottles
    CodeForces 667C Reberland Linguistics
    CodeForces 672D Robin Hood
    CodeForces 675E Trains and Statistic
    CodeForces 676D Theseus and labyrinth
  • 原文地址:https://www.cnblogs.com/liangxuru/p/7508877.html
Copyright © 2020-2023  润新知