IOS输入框聚焦会把内容区域顶起

打印 上一主题 下一主题

主题 782|帖子 782|积分 2346

前几天做了一个类似qq结构的h5的聊天界面,输入框固定在最底下。初始环境会有默认的两条聊天记载,但是当点击底部的输入框时,输入框聚焦,弹起键盘,然后整个界面就被顶上去了,然后那两条默认的聊天记载也被顶上去了,导致整个页面没内容了。
这张图片是初始页面

这张图片是点击输入框之后的样子,发现初始两条聊天内容被顶上去了

这里给出一个demo(如果样式有问题,请将欣赏器的模拟器调到iphone 6/7/8)
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8">
  5.   <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.   <meta name="viewport"
  7.     content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no,viewport-fit=cover" />
  8.   <title>Document</title>
  9.   <style>
  10.     * {
  11.       margin: 0;
  12.       padding: 0;
  13.       box-sizing: border-box;
  14.     }
  15.     html,
  16.     body {
  17.       width: 100%;
  18.       height: 100%;
  19.       overflow: hidden;
  20.       background-color: pink;
  21.     }
  22.     p {
  23.       padding-bottom: 1.875rem;
  24.     }
  25.     .left {
  26.       text-align: left;
  27.     }
  28.     .right {
  29.       text-align: right;
  30.       color: blue;
  31.     }
  32.     .chatContainer {
  33.       height: 100%;
  34.       padding-bottom: 30px;
  35.       overflow: auto;
  36.     }
  37.     .inputBox {
  38.       display: flex;
  39.       position: fixed;
  40.       bottom: 0;
  41.       left: 0;
  42.       right: 0;
  43.       height: 30px;
  44.       z-index: 999;
  45.     }
  46.     input {
  47.       flex: 1;
  48.       margin-right: .5rem;
  49.     }
  50.     button {
  51.       width: 6.25rem;
  52.       height: 100%;
  53.     }
  54.   </style>
  55. </head>
  56. <body>
  57.   <div class="chatContainer">
  58.     <div class="flag"></div>
  59.     <div class="chat">
  60.       <p class="left">你好,我是XXX,一个机器人</p>
  61.       <p class="left">请问您需要问什么</p>
  62.     </div>
  63.   </div>
  64.   <div class="inputBox">
  65.     <input type="text" />
  66.     <button>发送</button>
  67.   </div>
  68.   <script>
  69.     let oBtn = document.querySelector('button')
  70.     let oChatContainer = document.querySelector('.chatContainer')
  71.     let oChat = document.querySelector('.chat')
  72.     let oInput = document.querySelector('input')
  73.     oBtn.onmousedown = (e) => {
  74.       e.preventDefault()
  75.       let inputValue = oInput.value
  76.       if (!inputValue) return
  77.       let oDiv1 = document.createElement('p')
  78.       let oDiv2 = document.createElement('p')
  79.       oDiv1.className = 'right'
  80.       oDiv1.innerText = inputValue
  81.       oDiv2.className = 'left'
  82.       oDiv2.innerText = '感谢您的回复!'
  83.       oChat.appendChild(oDiv1)
  84.       oChat.appendChild(oDiv2)
  85.       let timer = setTimeout(() => {
  86.         clearTimeout(timer)
  87.         oDiv2.scrollIntoView({
  88.           behavior: "smooth",
  89.         })
  90.       }, 100)
  91.       oInput.value = ''
  92.     }
  93.   </script>
  94. </body>
  95. </html>
复制代码
感觉这个好像并没有什么问题,安卓可以正常的表现,交互。但是IOS就是不行,而且我还设置了
  1.   .inputBox {
  2.       position: fixed;
  3.       bottom: 0;
  4.       z-index: 999;
  5.     }
复制代码
让我百思不得其解,,最后发现这是IOS手机的通病,没办法,只能进行hack了。
我的终极解决思绪是,既然聚焦会定顶起内容区域,那么顶起来多少,我就用空缺的元素占位多少高度,如许内容就表现出来了。当手指在屏幕滑动时,再把占位块高度变为0。如果内容区域充足高了,那么就不需要占位了,因为这个时间肯定有内容区域的元素露出来了。
终极的js代码如下
  1. insetPlaceholder(oChatContainer, oInput)
  2. function insetPlaceholder(containerEl, inputEl) {
  3.   /**
  4.    * 只有苹果手机会导致输入框聚焦顶底整个内容区域,
  5.    * 所有这个函数只对IOS系统进行兼容处理
  6.    */
  7.   let isIos = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
  8.   if (!isIos) return
  9.   /**
  10.    * 这里这个是一个死的元素结构
  11.    * 类似这样
  12.    *  <div class="container">
  13.         <div class="flag"></div>
  14.         <div class="content"></div>
  15.       </div>
  16.     *  container是整体,flag是占位元素,根据情况切换高度
  17.     *  content是实际的内容区域
  18.     */
  19.   let oFlag = containerEl.children[0]
  20.   let oContent = containerEl.children[1]
  21.   let firstFocusFlagElHeight = undefined
  22.   // 能够显示出内容的最小高度
  23.   let showInfoMinHeight = undefined
  24.   const onInputFocus = () => {
  25.     /**
  26.      * 记录第一次聚焦的时候,container这个大盒子究竟被顶起来多少,把这个值记录为flag的高度
  27.      *
  28.      * 如果oContent的高度大于700了,那就说明内容足够多了,不需要占位元素顶了
  29.      */
  30.     if (firstFocusFlagElHeight === undefined || (oContent.offsetHeight < showInfoMinHeight)) {
  31.       let timer = setTimeout(() => {
  32.         clearTimeout(timer)
  33.         if (firstFocusFlagElHeight === undefined) {
  34.           firstFocusFlagElHeight = Math.abs(oFlag.getBoundingClientRect().top)
  35.           showInfoMinHeight = firstFocusFlagElHeight + oContent.offsetHeight
  36.         }
  37.         oFlag.style.height = firstFocusFlagElHeight + 'px'
  38.       }, 3e2)
  39.     }
  40.   }
  41.   oInput.addEventListener('focus', onInputFocus)
  42.   /**
  43.    * 监听这个事件主要是为了隐藏那个占位元素
  44.    * 防止用户滑动界面把占位元素露出来
  45.    * 并且很奇怪,如果不这样做,输入框会滚动!并且我已经设置了固定定位!
  46.    */
  47.   const onContainerElTouchstart = () => {
  48.     oFlag.style.height = 0
  49.     oInput.blur()
  50.   }
  51.   containerEl.addEventListener('touchstart', onContainerElTouchstart)
  52. }
复制代码
或者如果你的初始内容充足多,那你也不需要考虑这个问题
这里需要注意的是insetPlaceholder方法传入第一个参数是需要一个特定的html结构的,需要如许的结构
  1. <div class="container">
  2.    <div class="flag"></div>
  3.    <div class="content"></div>
  4. </div>
复制代码
另有两个注意点这里说一下


  1. oDiv2.scrollIntoView({
  2.   behavior: "smooth",
  3. })
复制代码
这段代码用setTimout包裹了,不然动画无法执行(IOS不支持这个方法,只有安卓可以)

  • 这里按钮的点击是监听的mousedown事件,并不是click,主要是为了阻止按钮点击触发输入框的失焦,会导致键盘收起,影响用户体验。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表