【问题标题】:How to prevent iOS keyboard from pushing the view off screen with CSS or JS如何使用 CSS 或 JS 防止 iOS 键盘将视图推离屏幕
【发布时间】:2016-12-01 20:46:34
【问题描述】:

我有一个响应式网页,当您点击按钮时会打开一个模式。当模态框打开时,它被设置为使用固定定位占据页面的整个宽度和高度。模态中还有一个输入字段。

在 iOS 设备上,当输入字段获得焦点时,键盘会打开。但是,当它打开时,它实际上会将整个文档向上推,这样我的页面的一半就超出了视口的顶部。我可以确认实际的html 标签本身已被向上推以补偿键盘,并且它没有通过 CSS 或 JavaScript 发生。

以前有没有人见过这种情况,如果有,有没有办法阻止它,或者在键盘打开后重新定位?这是一个问题,因为我需要用户能够在模式顶部看到内容,同时我想自动聚焦输入字段。

【问题讨论】:

  • @Iceman 不,我没有。我尝试搜索类似的问题,但没有找到。我试试看。
  • @rescuecreative 。我不确定这是否会有所帮助,因为此解决方案适用于 IOS8,因为我在 IOS8 和 Safari 上遇到了类似的问题。
  • @Iceman 我的环境不是phonegap,只是一个普通的网站。所以我不确定phonegap是否有什么不同,但这对我不起作用。
  • @rescuecreative 可能是新版本的问题。我会删除我的答案。

标签: javascript css responsive


【解决方案1】:

第一

<script type="text/javascript">
 $(document).ready(function() {
     document.ontouchmove = function(e){
          e.preventDefault();
          }
 });

然后这个

input.onfocus = function () {
    window.scrollTo(0, 0);
    document.body.scrollTop = 0;
}

【讨论】:

  • 谢谢!它完美地工作。顺便说一句,我只用document.body.scrollTop = 0;
  • 我试图解决一个问题 4 小时,直到我遇到你的答案。太感谢了。虽然只有input.onfocus = function () { window.scrollTo(0, 0); document.body.scrollTop = 0; } 是必需的。第一部分冻结页面。
【解决方案2】:

对于在 React 中遇到这个问题的任何人,我已经设法修复它,并采用这样的 @ankurJos 解决方案:

const inputElement = useRef(null);

useEffect(() => {
  inputElement.current.onfocus = () => {
    window.scrollTo(0, 0);
    document.body.scrollTop = 0;
  };
});

<input ref={inputElement} />

【讨论】:

    【解决方案3】:

    我为此苦苦挣扎了一段时间,找不到适合我的东西。

    我最终做了一些 JavaScript 骇客来让它工作。

    我发现如果输入元素位于屏幕的上半部分,Safari 不会推送视口。这就是我的小技巧的关键:

    我拦截了输入对象上的焦点事件,而是将焦点重定向到一个不可见的对象(transform: translateX(-9999px))。然后,一旦键盘出现在屏幕上(通常是 200 毫秒左右),我就会在原始元素上触发焦点事件,该元素已经在屏幕上显示动画。

    这是一种复杂的交互,但效果很好。

    function ensureOffScreenInput() {
      let elem = document.querySelector("#__fake_input");
      if (!elem) {
        elem = document.createElement("input");
        elem.style.position = "fixed";
        elem.style.top = "0px";
        elem.style.opacity = "0.1";
        elem.style.width = "10px";
        elem.style.height = "10px";
        elem.style.transform = "translateX(-1000px)";
        elem.type = "text";
        elem.id = "__fake_input";
        document.body.appendChild(elem);
      }
      return elem;
    }
    
    var node = document.querySelector('#real-input')
    var fakeInput = ensureOffScreenInput();
    
    function handleFocus(event) {
      fakeInput.focus();
    
      let last = event.target.getBoundingClientRect().top;
    
      setTimeout(() => {
        function detectMovement() {
          const now = event.target.getBoundingClientRect().top;
          const dist = Math.abs(last - now);
    
          // Once any animations have stabilized, do your thing
          if (dist > 0.01) {
            requestAnimationFrame(detectMovement);
            last = now;
          } else {
            event.target.focus();
            event.target.addEventListener("focus", handleFocus, { once: true });
          }
        }
        requestAnimationFrame(detectMovement);
      }, 50);
    }
    
    node.addEventListener("focus", handleFocus, { once: true });
    

    我个人在 Svelte 操作中使用此代码,它在我的 Apple Maps 的 Svelte PWA 克隆中运行良好。

    Video of it working in a PWA clone of Apple Maps

    您会在视频中注意到,在输入到视口上半部分的动画稳定后,自动完成功能会发生变化。这就是焦点切换的发生。

    此 hack 的唯一缺点是原始实现上的焦点处理程序将运行两次,但有一些方法可以通过元数据来解决这一问题。

    【讨论】:

    • 这是唯一对我有用的东西。谢谢
    【解决方案4】:

    如果你不想滚动到顶部(0, 0),你也可以这样做

    window.scrollBy(0, 0)
    

    【讨论】:

      【解决方案5】:

      在某些情况下,可以通过重新调整输入元素的焦点来缓解此问题。

      input.onfocus = function () {
        this.blur();
        this.focus();
      }
      

      【讨论】:

      • 这种方式会挂掉设备。想象一下在无限时间内模糊和重新聚焦同一个元素。
      【解决方案6】:

      IOS8 和 Safari 浏览器在页面加载后发生的 input.focus() 行为相同。他们都缩放到元素并调出键盘。(不太确定这是否会有所帮助,但您是否尝试过使用类似的东西?)

      HTML 是

      <input autofocus>
      

      JS 是

      for (var i = 0; i < 5; i++) {
      document.write("<br><button onclick='alert(this.innerHTML)'>" + i + "</button>");
      }
      
      //document.querySelector('input').focus();
      

      CSS

      button {
      width: 300px;
      height: 40px;
      }
      

      此外,您还必须使用用户代理解决方法,您可以将其用于所有 IOS 版本

      if (!/iPad|iPhone|iPod/g.test(navigator.userAgent)) {
      element.focus();
      }
      

      【讨论】:

      • 对不起,也许我不明白。按钮和警报有什么帮助?
      • @rescuecreative 我想我理解错了。我在想,也许您正试图在页面触摸后显示虚拟键盘和滚动。
      • 啊,我明白了。不,我试图阻止虚拟键盘将 DOM 推到视口之外
      • @rescuecreative 只是一个建议您是否尝试过使用下面提到的这两个选项?
      猜你喜欢
      • 2020-12-11
      • 2019-01-12
      • 2011-12-04
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      • 2017-11-03
      • 2011-05-11
      • 1970-01-01
      相关资源
      最近更新 更多