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

news/2024/7/20 21:10:46 标签: ios, 前端, javascript

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

这里给出一个demo(如果样式有问题,请将浏览器的模拟器调到iphone 6/7/8)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no,viewport-fit=cover" />
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      width: 100%;
      height: 100%;
      overflow: hidden;
      background-color: pink;
    }

    p {
      margin-bottom: 1.875rem;
    }


    .left {
      text-align: left;
    }

    .right {
      text-align: right;
      color: blue;
    }

    .chatContainer {
      height: 100%;
      overflow: auto;
    }

    .inputBox {
      display: flex;
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      height: 1.875rem;
      z-index: 999;
    }

    input {
      flex: 1;
      margin-right: .5rem;
    }

    button {
      width: 6.25rem;
      height: 100%;
    }
  </style>
</head>

<body>
  <div class="chatContainer">
    <div class="flag"></div>
    <div class="chat">
      <p class="left">你好,我是XXX,一个机器人</p>
      <p class="left">请问您需要问什么</p>
    </div>
  </div>
  <div class="inputBox">
    <input type="text" />
    <button>发送</button>
  </div>

  <script>javascript">
    let oBtn = document.querySelector('button')
    let oChatContainer = document.querySelector('.chatContainer')
    let oInput = document.querySelector('input')
    let oFlag = document.querySelector('.flag')
    oBtn.onclick = () => {
      let inputValue = oInput.value
      if (!inputValue) return
      let oDiv1 = document.createElement('p')
      let oDiv2 = document.createElement('p')
      oDiv1.className = 'right'
      oDiv1.innerText = inputValue
      oDiv2.className = 'left'
      oDiv2.innerText = '感谢您的回复!'
      oChatContainer.appendChild(oDiv1)
      oChatContainer.appendChild(oDiv2)
      oDiv2.scrollIntoView({
        behavior: "smooth"
      })
      oInput.value = ''
    }
  </script>
</body>

</html>

感觉这个好像并没有什么问题,安卓可以正常的显示,交互。但是IOS就是不行,并且我还设置了

  .inputBox {
      display: flex;
      bottom: 0;
      z-index: 999;
    }

让我百思不得其解,,最后发现这是IOS手机的通病,没办法,只能进行hack了。

我的最终解决思路是,既然聚焦会定顶起内容区域,那么顶起来多少,我就用空白的元素占位多少高度,这样内容就显示出来了。当手指在屏幕滑动时,再把占位块高度变为0。如果内容区域的高度大于了被顶起的高度(或者内容区域的高度多出了被顶起的高度20px之类的),那么就不需要占位了,因为这个时候肯定有内容区域的元素露出来了。

最终的js代码如下

javascript">insetPlaceholder(oChatContainer, oInput)
function insetPlaceholder(containerEl, inputEl) {
  // 只有苹果手机会导致输入框聚焦顶底整个内容区域,所有这个函数只对IOS系统进行兼容处理
  let isIos = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
  if (!isIos) return

  /**
   * 这里这个是一个死的元素结构
   * 类似这样
   *  <div class="container">
        <div class="flag"></div>
        <div class="content"></div>
      </div>
    *  container是整体,flag是占位元素,根据情况切换高度
    *  content是实际的内容区域
    */
  let oFlag = containerEl.children[0]
  let oContent = containerEl.children[1]
  let containerElTouchstartIsRemove = false
  /**
   * 记录第一次聚焦的时候,container这个大盒子究竟被顶起来多少,把这个值记录为flag的高度
   * 以后每次聚焦都会和这个值做比较,如果content的高度大于了顶起来的高度,那么说明内容已经足够多了,所以就不需要flag来占位了,然后把 flagEl 高度设置为0
   */
  let isFirstFocusFlagElHeight = undefined

  const onInputFocus = () => {
    isFirstFocusFlagElHeight === undefined && (isFirstFocusFlagElHeight = Math.abs(oFlag.getBoundingClientRect().top))
    let insetPlaceholderHeight = isFirstFocusFlagElHeight - oContent.offsetHeight
    if (insetPlaceholderHeight > 0) {
      setTimeout(() => {
        oFlag.style.height = insetPlaceholderHeight
      }, 3e2)
    } else {
      if (!containerElTouchstartIsRemove) {
        containerEl.removeEventListener('touchstart', onContainerElTouchstart)
        containerElTouchstartIsRemove = true
      }
    }
  }

  oInput.addEventListener('focus', onInputFocus)
  /**
   * 监听这个事件主要是为了隐藏那个占位元素
   * 防止用户滑动界面把占位元素露出来
   * 并且很奇怪,如果不这样做,输入框会滚动!并且我已经设置了固定定位!
   * 如果占位元素没有了,那就可以把这个事件移除了
   * 
   */
  const onContainerElTouchstart = () => {
    if (oFlag.style.height > 0) {
      oFlag.style.height = 0
      oInput.blur()
    }
  }
  containerEl.addEventListener('touchstart', onContainerElTouchstart)
}

或者如果你的初始内容足够多,那你也不需要考虑这个问题

这里需要注意的时我的insetPlaceholder方法时需要一个特定的html结构的,需要这样的结构

<div class="container">
   <div class="flag"></div>
   <div class="content"></div>
</div>

http://www.niftyadmin.cn/n/5198620.html

相关文章

【广州华锐互动】VR虚拟现实技术助力太空探险:穿越时空,探索宇宙奥秘

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐走进我们的生活。在教育领域&#xff0c;VR技术的应用也日益广泛&#xff0c;为学生提供了更加生动、直观的学习体验。本文将以利用VR开展太空探险学习为主题&#xff0c;探讨如何将这一先进技术…

数据分析基础之《jupyter notebook工具》

一、安装库 1、linux库 yum install python3-devel 2、python库 pip3 install -U matplotlib pip3 install -U numpy pip3 install -U pandas pip3 install -U TA-Lib pip3 install -U tables pip3 install -U notebook 3、如果TA-Lib安装不上&#xff0c;先手动安装依赖库 …

Linux:动静态库

目录 一、软硬链接 1、软链接 2、硬链接 二、动态库和静态库 编写一个库 ①静态库 使用静态库的方法 ②动态库 使用动态库的方法 库存在的意义 一、软硬链接 软硬链接的本质区别就是&#xff1a;有无独立的inode 软链接有独立的inode&#xff0c;也就意味着软链接是一…

Ubuntu18.04运行gazebo的launch文件[model-4] process has died报错

启动gazebo仿真环境报错[model-4] process has died [model-4] process has died [pid 2059, exit code 1, cmd /opt/ros/melodic/lib/gazebo_ros/spawn_model -urdf -model mycar -param robot_description __name:model __log:/root/.ros/log/8842dc14-877c-11ee-a9d9-0242a…

机器学习二元分类 二元交叉熵 二元分类例子

二元交叉熵损失函数 深度学习中的二元分类损失函数通常采用二元交叉熵&#xff08;Binary Cross-Entropy&#xff09;作为损失函数。 二元交叉熵损失函数的基本公式是&#xff1a; L(y, y_pred) -y * log(y_pred) - (1 - y) * log(1 - y_pred)其中&#xff0c;y是真实标签&…

某60区块链安全之不安全的随机数实战二学习记录

区块链安全 文章目录 区块链安全不安全的随机数实战二实验目的实验环境实验工具实验原理实验内容EXP利用 不安全的随机数实战二 实验目的 学会使用python3的web3模块 学会以太坊不安全的随机数漏洞分析及利用 实验环境 Ubuntu18.04操作机 实验工具 python3 实验原理 由…

【亚马逊云科技产品测评】活动征文|aws云服务器 + 微服务Spring Cloud Nacos 实战

文章目录 前言一、拥有一台Aws Linux服务器1.1、选择Ubuntu版本Linux系统1.2、创建新密钥对1.3、网络设置1.4、配置成功&#xff0c;启动实例1.5、回到实例区域1.6、进入具体的实例1.7、设置安全组 二、在Mac上连接Aws云服务&#xff0c;并安装配置JDK112.1、解决离奇的错误2.2…

Spring Boot - 自定义注解来记录访问路径以及访问信息,并将记录存储到MySQL

1、准备阶段 application.properties&#xff1b;yml 可通过yaml<互转>properties spring.datasource.urljdbc:mysql://localhost:3306/study_annotate spring.datasource.usernameroot spring.datasource.password123321 spring.datasource.driver-class-namecom.mysq…