JQuery 移动面板小部件 - 打开可折叠列表会导致一旦展开超出页面高度,就会跳转到页面 div 的底部。为啥?

Posted

技术标签:

【中文标题】JQuery 移动面板小部件 - 打开可折叠列表会导致一旦展开超出页面高度,就会跳转到页面 div 的底部。为啥?【英文标题】:JQuery Mobile Panel Widget – opening collapsible lists causes jump scroll to bottom of page div once expanded beyond page height. Why?JQuery 移动面板小部件 - 打开可折叠列表会导致一旦展开超出页面高度,就会跳转到页面 div 的底部。为什么? 【发布时间】:2018-10-11 21:05:27 【问题描述】:

尝试使用 JQuery Mobile 的 (v 1.4.5) 面板小部件构建可折叠的多级菜单。我添加了一些上滑/下滑动画,使子菜单的打开更加明显。

<div data-role="page">

<div data-role="panel" id="mainmenu" role="navigation" data-display="overlay">
  <ul data-role="listview" class="ui-listview-outer">
    <li><a href="#">Home Page</a></li>
    <li data-role="collapsible" data-inset="false">
      <h3>LIST 1 OF 6</h3>
      <ul data-role="listview" data-theme="b">
        <li><a href="#">1.1</a></li>
        <li><a href="#">1.2</a></li>
        <li><a href="#">1.3</a></li>
        <!-- etc. -->
      </ul>
    </li>
    <li data-role="collapsible" data-inset="false">
      <h3>List 2 OF 6</h3>
      <ul data-role="listview" data-theme="c">
        <li role="menuitem"><a href="#">2.1</a></li>
        <li role="menuitem"><a href="#">2.2</a></li>
        <li role="menuitem"><a href="#">2.3</a></li>
        <!-- etc. -->
      </ul>
    </li>
    <li data-role="collapsible" data-inset="false">
      <h3>List 3 OF 6</h3>
      <ul data-role="listview">
        <li><a href="#">3.1</a></li>
        <li><a href="#">3.2</a></li>
        <li><a href="#">3.3</a></li>
        <!-- etc. -->
      </ul>
    </li>
    <li data-role="collapsible" data-inset="false">
      <h3>LIST 4 OF 6</h3>
      <ul data-role="listview">
        <li><a href="#">4.1</a></li>
        <li><a href="#">4.2</a></li>
        <li><a href="#">4.3</a></li>
        <!-- etc. -->
      </ul>
    </li>
    <li data-role="collapsible" data-inset="false">
      <h3>LIST 5 of 6</h3>
      <ul data-role="listview">
        <li><a href="#">5.1</a></li>
        <li><a href="#">5.2</a></li>
        <li><a href="#">5.3</a></li>
        <!-- etc. -->
      </ul>
    </li>
    <li data-role="collapsible" data-inset="false">
      <h3>LIST 6 OF 6</h3>
      <ul data-role="listview">
        <li><a href="#">6.1</a></li>
        <li><a href="#">6.2</a></li>
        <li><a href="#">6.3</a></li>
        <!-- etc. -->
      </ul>
      </li>
  </ul>
</div>

<div data-role="header" class="header">
<a href="#mainmenu" data-icon="bars" data-iconpos="notext">Menu</a><h1>This is the header
</h1>
</div>

<div data-role="content" class="content">
This is the content
<br>
<br>
<br>
<br>
<!-- <br>'s etc. to increase page length for illustrative purposes -->
</div>

<div data-role="footer" class="footer">
This is the footer
</div>

</div>

问题:当菜单的高度超过页面 div 的高度时(由于最上面的子菜单很长,这种情况很快就会发生),然后 另一个 更下方的子菜单被展开/折叠,视口跳转使得页面底部位于视口底部,将新打开的子菜单推到视口下方,无疑会使用户对刚刚发生的事情感到困惑。

理想情况下,刚刚单击的子菜单保持在视图中,slideDown 动画可见并且用户理解子菜单已打开。 JQuery 似乎是根据菜单高度动态改变页面高度,这是有道理的,但视口的突然移动......不是那么回事。

无论有没有幻灯片动画,该行为都会持续存在,如下所示:

$(document).ready(function () 

  $(document).on("collapsibleexpand", ".ui-collapsible", function (event) 
        var contentDiv = $(this).children(".ui-collapsible-content");
        contentDiv.hide();
        contentDiv.slideDown(300);
        event.stopPropagation(); // don't bubble up
    );

    $(document).on("collapsiblecollapse", ".ui-collapsible", function (event) 
        var contentDiv = $(this).children('.ui-collapsible-content');
        contentDiv.slideUp(300);
        event.stopPropagation(); // don't bubble up
    );
); 

Working fiddle to show the issue

我远不是一个 JQuery/JS/JQM 专家,我在这里做的事情很可能是不推荐的(例如,我没有看到太多关于在导航面板中嵌套列表的内容) .如果是这样,我愿意听到。

【问题讨论】:

我相信你需要两个滚动条,一个用于面板,一个用于页面内容,然后设置面板 scrollTop() 【参考方案1】:

这是我对这种导航系统的建议。恕我直言,应该有两个可滚动元素,页面内容和菜单子系统(侧面板)。

我不能完全理解你的句子...视口跳跃使得页面底部位于视口的底部”但无论如何,我喜欢你的滑动想法子菜单,所以我认为这里的困难是:如何计算将当前菜单项移动到顶部所需的滚动量。

请注意,我并未在所有情况下都测试过这段代码,但乍一看,它似乎没问题 - 至少在浏览器中是这样。

$(document).ready(function() 
  $(document).on("collapsibleexpand", ".ui-collapsible", function(e) 
    var self = $(this), 
        menu = $("#mainmenu"),
        pageY = $(document).scrollTop(),
        content = $(this).children(".ui-collapsible-content");
    content.hide();
    content.slideDown(
        duration: 300,
        step: function(now, fx) 
          if (fx.prop == "height") 
            var pct = ((100 * now) / fx.end),
              itemTop = $(self).offset().top,
              menuScrollTop = $(menu).scrollTop(),
              amt = (itemTop - pageY) / 100 * pct;
            menu.scrollTop(menuScrollTop + amt);
          
        
      
    );
    e.stopPropagation(); // don't bubble up
  );

  $(document).on("collapsiblecollapse", ".ui-collapsible", function(e) 
    var content = $(this).children('.ui-collapsible-content');
    content.slideUp(300);
    e.stopPropagation(); // don't bubble up
  );
);
.content 
  text-align: center;


#mainmenu 
  position: fixed;
  overflow-y: scroll;
  height: 100%;


.ui-page-active 
  overflow-y: scroll;
  min-height: 100% !important;


li,
ul 
  padding: 0 !important;


h3 
  margin: 0 !important;
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css">
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
</head>
<body>
  <div data-role="page">
    <div data-role="panel" id="mainmenu" role="navigation" data-display="overlay">
      <ul data-role="listview" class="ui-listview-outer">
        <li><a href="#">Home Page</a></li>
        <li data-role="collapsible" data-inset="false">
          <h3>LIST 1 OF 6</h3>
          <ul data-role="listview" data-theme="b">
            <li><a href="#">1.1</a></li>
            <li><a href="#">1.2</a></li>
            <li><a href="#">1.3</a></li>
            <li><a href="#">1.4</a></li>
            <li><a href="#">1.5</a></li>
            <li><a href="#">1.6</a></li>
            <li><a href="#">1.7</a></li>
            <li><a href="#">1.8</a></li>
            <li><a href="#">1.9</a></li>
            <li><a href="#">1.10</a></li>
            <li><a href="#">1.11</a></li>
            <li><a href="#">1.12</a></li>
            <li><a href="#">1.13</a></li>
            <li><a href="#">1.14</a></li>
            <li><a href="#">1.15</a></li>
            <li><a href="#">1.16</a></li>
            <li><a href="#">1.17</a></li>
            <li><a href="#">1.18</a></li>
            <li><a href="#">1.19</a></li>
            <li><a href="#">1.20</a></li>
            <li><a href="#">1.21</a></li>
            <li><a href="#">1.22</a></li>
            <li><a href="#">1.23</a></li>
            <li><a href="#">1.24</a></li>
            <li><a href="#">1.25</a></li>
            <li><a href="#">1.26</a></li>
            <li><a href="#">1.27</a></li>
            <li><a href="#">1.28</a></li>
            <li><a href="#">1.29</a></li>
          </ul>
        </li>
        <li data-role="collapsible" data-inset="false">
          <h3>List 2 OF 6</h3>
          <ul data-role="listview" data-theme="c">
            <li><a href="#">2.1</a></li>
            <li><a href="#">2.2</a></li>
            <li><a href="#">2.3</a></li>
            <li><a href="#">2.4</a></li>
            <li><a href="#">2.5</a></li>
            <li><a href="#">2.6</a></li>
            <li><a href="#">2.7</a></li>
            <li><a href="#">2.8</a></li>
            <li><a href="#">2.9</a></li>
            <li><a href="#">2.10</a></li>
            <li><a href="#">2.11</a></li>
            <li><a href="#">2.12</a></li>
            <li><a href="#">2.13</a></li>
            <li><a href="#">2.14</a></li>
            <li><a href="#">2.15</a></li>
            <li><a href="#">2.16</a></li>
          </ul>
        </li>
        <li data-role="collapsible" data-inset="false">
          <h3>List 3 OF 6</h3>
          <ul data-role="listview">
            <li><a href="#">3.1</a></li>
            <li><a href="#">3.2</a></li>
            <li><a href="#">3.3</a></li>
            <li><a href="#">3.4</a></li>
            <li><a href="#">3.5</a></li>
            <li><a href="#">3.6</a></li>
            <li><a href="#">3.7</a></li>
          </ul>
        </li>
        <li data-role="collapsible" data-inset="false">
          <h3>LIST 4 OF 6</h3>
          <ul data-role="listview">
            <li><a href="#">4.1</a></li>
            <li><a href="#">4.2</a></li>
            <li><a href="#">4.3</a></li>
          </ul>
        </li>
        <li data-role="collapsible" data-inset="false">
          <h3>LIST 5 of 6</h3>
          <ul data-role="listview">
            <li><a href="#">5.1</a></li>
            <li><a href="#">5.2</a></li>
            <li><a href="#">5.3</a></li>
            <li><a href="#">5.4</a></li>
            <li><a href="#">5.5</a></li>
            <li><a href="#">5.6</a></li>
            <li><a href="#">5.7</a></li>
            <li><a href="#">5.8</a></li>
            <li><a href="#">5.9</a></li>
            <li><a href="#">5.10</a></li>
          </ul>
        </li>
        <li data-role="collapsible" data-inset="false">
          <h3>LIST 6 OF 6</h3>
          <ul data-role="listview">
            <li><a href="#">6.1</a></li>
            <li><a href="#">6.2</a></li>
            <li><a href="#">6.3</a></li>
            <li><a href="#">6.4</a></li>
            <li><a href="#">6.5</a></li>
            <li><a href="#">6.6</a></li>
            <li><a href="#">6.7</a></li>
            <li><a href="#">6.8</a></li>
            <li><a href="#">6.9</a></li>
            <li><a href="#">6.10</a></li>
          </ul>
        </li>
      </ul>
    </div>
    <div data-role="header" class="header">
      <a href="#mainmenu" data-icon="bars" data-iconpos="notext">Menu</a>
      <h1>This is the header</h1>
    </div>
    <div data-role="content" class="content">
      This is the content
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
    </div>
    <div data-role="footer" class="footer">
      <h1>This is the footer</h1>
    </div>
  </div>
</body>
</html>

请在您所有可用的设备上测试上述方法并给我反馈。

【讨论】:

谢谢你。我会试一试,让你知道!是的,我很难对视口的变化做出描述——或者甚至只是弄清楚一开始到底发生了什么。本质上,如果您一次打开多个子菜单,使得菜单的高度变得比 data-role="page" div 长,打开任何进一步的子菜单都会导致视图“跳转滚动”(缺少更好的突然变化的术语),将页脚定位在浏览器视口的底部(在 Chrome 和 Safari 中),让人迷失方向。最糟糕的事情...... 这个,我的朋友,在我尝试过的每一个真实和虚拟设备上都能完美运行。简单,优雅,绝对可爱......两个滚动条解决方案绝对是要走的路。我特别喜欢所选子菜单如何将自身重新定位在视口顶部——UI 黄金,并解决了许多问题。把它带到实际项目中,它真是太棒了。一个+。非常非常感谢。

以上是关于JQuery 移动面板小部件 - 打开可折叠列表会导致一旦展开超出页面高度,就会跳转到页面 div 的底部。为啥?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery Mobile - 仅使可折叠小部件的某些部分处于活动状态

Flipswitch小部件呈现为外部面板小部件中的下拉列表

单击打开 jQuery Mobile 面板小部件时的 Google 地图指针

jQuery UI组件构成——小部件(Widgets)

06 Jquery UI Accodion 可折叠面板插件

jQuery Accordion 功能面板在不应该打开时打开