开发者问题收集

Telegram Bot 的 Web 应用程序中滚动时出现折叠错误

2023-08-05
3176

我想在 Telegram 中构建用 Flutter 编写的移动 Web 应用程序。同时,存在一个问题:向下滚动时,应用程序会折叠,就像我正在折叠底部工作表一样。

Web App ; Telegram Web App ; 问题的视频演示

我设法通过在代码中添加以下脚本来解决 iOS 设备上的这个问题:

document.addEventListener("touchmove", function (event) {
    event.preventDefault();
},
    {
        passive: false
    });

但在 Android 上,问题仍然存在。我尝试了使用 touchmove、overflow、relative 和其他方法来禁用页面上的滚动的所有变体。我找到的所有方法都无法解决 Android 上的问题。

3个回答

将其添加到 css 中的 body 部分以禁用任何触摸事件:

body {
    touch-action: none !important;
}
Big Zak
2023-08-25

您在 Telegram Web App 中滚动或向下滑动时遇到的折叠问题是一个常见问题。我自己也遇到过类似的问题,我发现了一个有效解决该问题的解决方案。

视觉比较:

在深入研究解决方案之前,让我们直观地观察一下这个问题。下面是两个 GIF,分别展示了实施解决方案前后的问题。

在此处输入图片说明 在此处输入图片说明
Bug
向下滑动 Telegram Mini App
会导致其折叠而不是滚动*
已修复
向下滑动 Telegram Mini App
现在可在问题修复后正确滚动内容!*

现在我们已经看到了问题的实际效果,让我们继续实施解决方案。我将提供解决问题的分步指南。

分步解决方案:

1.确保文档可滚动:

首先,必须确保文档可滚动。我们通过检查文档的滚动高度是否大于视口高度来实现这一点。如果不大于,我们将相应地调整文档的高度。

// Ensure the document is scrollable
function ensureDocumentIsScrollable() {
  const isScrollable =
    document.documentElement.scrollHeight > window.innerHeight;
  // Check if the document is scrollable
  if (!isScrollable) {
    /*
    Set the document's height to 100 % of
    the viewport height plus one extra pixel
    to make it scrollable.
    */
    document.documentElement.style.setProperty(
      "height",
      "calc(100vh + 1px)",
      "important"
    );
  }
}

// Call ensureDocumentIsScrollable function when the entire page has loaded.
window.addEventListener("load", ensureDocumentIsScrollable);

2. 防止 window.scrollY 变为零:

接下来,我们防止在可滚动元素上向下滑动时 window.scrollY 变为零。这可以防止向下滑动时意外折叠。

// Prevent windwo.scrollY from becoming zero
function preventCollapse(event) {
  if (window.scrollY === 0) {
    window.scrollTo(0, 1);
  }
}

// Attach the above function to the touchstart event handler of the scrollable element
const scrollableElement = document.querySelector(".scrollable-element");
scrollableElement.addEventListener("touchstart", preventCollapse);

现在我们已经概述了步骤,让我们将解决方案集成到您的代码中。以下是完整的代码片段。我删除了不必要的代码和样式,以便更好地理解代码。

<html>
  <head>
    <style>
      .scrollable-element {
        overflow-y: scroll;
        height: 32rem;
        font-size: 6.25rem;
        border: 1px solid;
      }
    </style>
  </head>
  <body>
    <div class="scrollable-element">
      <div>Item 1</div>
      <div>Item 2</div>
      <div>Item 3</div>
      <div>Item 4</div>
      <div>Item 5</div>
      <div>Item 6</div>
      <div>Item 7</div>
      <div>Item 8</div>
      <div>Item 9</div>
      <div>Item 10</div>
    </div>
    <script>
      function ensureDocumentIsScrollable() {
        const isScrollable =
          document.documentElement.scrollHeight > window.innerHeight;
        if (!isScrollable) {
          document.documentElement.style.setProperty(
            "height",
            "calc(100vh + 1px)",
            "important"
          );
        }
      }
      function preventCollapse() {
        if (window.scrollY === 0) {
          window.scrollTo(0, 1);
        }
      }

      const scrollableElement = document.querySelector(".scrollable-element");
      scrollableElement.addEventListener("touchstart", preventCollapse);

      window.addEventListener("load", ensureDocumentIsScrollable);
    </script>
  </body>
</html>

通过实施这些调整,您的 Telegram Mini App 在向下滚动时将不再遭受意外崩溃。

我鼓励您为 Telegram Web App 部署提供的代码并亲自观察结果。

此外,您可以在 Telegram Mini App 上体验修复效果,我已将此解决方案应用于: @theme_inspector_bot

nimaxin
2024-05-28

共有3个步骤:添加样式、添加滚动和添加延迟

  1. index.html 中的 head 标签下添加此样式:

    <style>
    body {
    height: 1000vh !important;
    position: static !important;
    overscroll-behavior: none;
    }
    
    flutter-view {
    position: fixed !important;
    max-width: 100vw !important;
    max-height: 100vh !important;
    }
    
    /* Safari 特定的 CSS */
    @supports (-webkit-touch-callout: inherit) {
    body {
    height: 1000vh !important;
    }
    }
    </style>
    
    1. index.html 中的 body 标签下添加滚动脚本:
 <script>window.scroll(0, window.document.body.scrollHeight);</script>
  1. (可选)有时 Telegram 加载速度不快,因此在 ma​​in.dart 中添加一些延迟:

     void main() async {
    await Future.delayed(const Duration(milliseconds: 500));
    }
    

您可以关注类似的 github 问题 此处

Khamidjon Khamidov
2024-06-24