• 移动端踩坑之旅-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/   

  • 相关阅读:
    学习进度总结表
    关于软件工程的问题
    自我介绍
    web安全
    spring profile
    spring 装配
    python Descriptor (描述符)
    python string intern
    Java 对象内存占用
    java jdb命令详解
  • 原文地址:https://www.cnblogs.com/liangxuru/p/7508877.html
Copyright © 2020-2023  润新知