【问题标题】:Collapsible panel with variable content height具有可变内容高度的可折叠面板
【发布时间】:2021-04-30 01:16:41
【问题描述】:

几个标签的内容高度不同(例如,一个比另一个有更多的文本),但在子标签之间切换时,父可折叠面板不会调整大小。如何将父级可折叠面板内容更改为与子选项卡高度匹配的最大高度?还是根据标签高度设置最大高度?

编辑 2:片段现在包含 CSS 活动类

编辑:找到半解决方案!
在 JavaScript 中,不要使用此代码:

content.style.maxHeight = content.scrollHeight + "px";

我把它改成了以下:

content.style.maxHeight = "initial";

这可行,但它带来了一个新问题。因为现在 CSS 过渡不再像使用 scrollHeight 时那样工作:

.calendar-unfold {
    max-height: 0;
    transition: max-height 0.4s ease-out;
}

片段:

var coll = document.getElementsByClassName("calendar-fold");
  var i;
  for (i = 0; i < coll.length; i++) {
    coll[i].addEventListener("click", function () {
      this.classList.toggle("active");
      var content = this.nextElementSibling;
      if (content.style.maxHeight) {
        content.style.maxHeight = null;
      } else {
        content.style.maxHeight = content.scrollHeight + "px";
      }
    });
  }
  /* CALENDAR TABS 3*/
  function calendarTabCalendarBtn3(){
    document.getElementById('calendarTabCalendar3').style.display ='block';
    document.getElementById('calendarTabPruning3').style.display ='none';
    document.getElementById('calendarTabPregrow3').style.display ='none';
    document.getElementById('calendarTabAftergrow3').style.display ='none';
    document.getElementById('calendarTabNeighbour3').style.display ='none';
  }
  function calendarTabPruningBtn3(){
    document.getElementById('calendarTabCalendar3').style.display ='none';
    document.getElementById('calendarTabPruning3').style.display ='block';
    document.getElementById('calendarTabPregrow3').style.display ='none';
    document.getElementById('calendarTabAftergrow3').style.display ='none';
    document.getElementById('calendarTabNeighbour3').style.display ='none';
  }
  function calendarTabPregrowBtn3(){
    document.getElementById('calendarTabCalendar3').style.display ='none';
    document.getElementById('calendarTabPruning3').style.display ='none';
    document.getElementById('calendarTabPregrow3').style.display ='block';
    document.getElementById('calendarTabAftergrow3').style.display ='none';
    document.getElementById('calendarTabNeighbour3').style.display ='none';
  }
  function calendarTabAftergrowBtn3(){
    document.getElementById('calendarTabCalendar3').style.display ='none';
    document.getElementById('calendarTabPruning3').style.display ='none';
    document.getElementById('calendarTabPregrow3').style.display ='none';
    document.getElementById('calendarTabAftergrow3').style.display ='block';
    document.getElementById('calendarTabNeighbour3').style.display ='none';
  }
  function calendarTabNeighbourBtn3(){
    document.getElementById('calendarTabCalendar3').style.display ='none';
    document.getElementById('calendarTabPruning3').style.display ='none';
    document.getElementById('calendarTabPregrow3').style.display ='none';
    document.getElementById('calendarTabAftergrow3').style.display ='none';
    document.getElementById('calendarTabNeighbour3').style.display ='block';
  }
.calendar-fold {
    margin: 4px;
    padding: 10px;
    font-size: 1.25em!important;
    background-color: rgba(255,255,255,1.00);
    border: 1px solid rgba(55,175,75,1.00);
    color: rgba(55,175,75,1.00);
    border-radius: 5px;
    cursor: pointer;
    transition: 0.4s;
}
.calendar-fold:hover {
    border: 1px solid rgba(0,145,255,1.00);
    color: rgba(0,145,255,1.00);
}
.calendar-fold.active {
    background-color: rgba(55,175,75,1.00);
    border: 1px solid rgba(55,175,75,1.00);
    color: rgba(255,255,255,1.00);
}
.calendar-fold.active:hover {
    background-color: rgba(55,175,75,0.80);
    border: 1px solid rgba(55,175,75,0.00);
    color: rgba(255,255,255,1.00);
}
.calendar-unfold {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.4s ease-out;
    background-color: rgba(200,200,200,1.00);
}
.calendar-tabbuttongroup {
    width: calc(100% - 8px);
    margin: 0 4px;
}
.calendar-tabbutton {
    background-color: rgba(55,175,75,1.00);
    color: rgba(255,255,255,1.00);
    padding: 8px;
    font-size: 1.00em;
    float: left;
    width: 10%;
    cursor: pointer;
}
.calendar-tabbutton:hover {
    background-color: rgba(55,175,75,0.80);
}
.calendar-tabgroup {
    float: left;
    width: 100%;
}
.calendar-tabcontent {
    width: 100%;
    padding: 0 0 8px 0;
}
#calendarTabCalendar3 { display: block; }
#calendarTabPruning3 { display: none; }
#calendarTabPregrow3 { display: none; }
#calendarTabAftergrow3 { display: none; }
#calendarTabNeighbour3 { display: none; }
<div class="calendar-fold">Collapsible</div>
<div class="calendar-unfold">
  <div class="calendar-tabbuttongroup">
    <div class="calendar-tabbutton calendarTabbtnCalendar" onclick="calendarTabCalendarBtn3();">Btn 1</div>
    <div class="calendar-tabbutton calendarTabbtnPruning" onclick="calendarTabPruningBtn3();">Btn 2</div>
    <div class="calendar-tabbutton calendarTabbtnPregrow" onclick="calendarTabPregrowBtn3();">Btn 3</div>
    <div class="calendar-tabbutton calendarTabbtnAftergrow" onclick="calendarTabAftergrowBtn3();">Btn 4</div>
    <div class="calendar-tabbutton calendarTabbtnNeighbour" onclick="calendarTabNeighbourBtn3();">Btn 5</div>
  </div>
  <div class="calendar-tabgroup">
    <div class="calendar-tabcontent" id="calendarTabCalendar3">
      <div class="calendar-moreinfo">
        <p class="calendar-pc">
          Some default content<br>
          Some default content<br>
          Some default content
          <hr>
        </p>
      </div>
    </div>
    <div class="calendar-tabcontent" id="calendarTabPruning3">
      <div class="calendar-moreinfo">
        <p class="calendar-pc">
          Some small content<br>
          Some small content
          <hr>
        </p>
      </div>
    </div>
    <div class="calendar-tabcontent" id="calendarTabPregrow3">
      <div class="calendar-moreinfo">
        <p class="calendar-pc">
          Some large content<br>
          Some large content<br>
          Some large content<br>
          Some large content<br>
          Some large content<br>
          Some large content
          <hr>
        </p>
      </div>
    </div>
    <div class="calendar-tabcontent" id="calendarTabAftergrow3">
      <div class="calendar-moreinfo">
        <p class="calendar-pc">
          Some medium content<br>
          Some medium content<br>
          Some medium content<br>
          Some medium content
          <hr>
        </p>
      </div>
    </div>
    <div class="calendar-tabcontent" id="calendarTabNeighbour3">
      <div class="calendar-moreinfo">
        <p class="calendar-pc">
          Some small content<br>
          Some small content
          <hr>
        </p>
      </div>
    </div>
  </div>
</div>

【问题讨论】:

  • 虽然面板不应该需要最大高度;块元素只有它需要的大小。它应该根据内部最高元素的高度调整大小。如果您需要这方面的帮助,我们需要一个合适的minimal reproducible example
  • 我们至少需要查看 HTML 以便getElementsByClassName("calendar-fold") 将返回一个我们可以检查的有用集合。
  • 谢谢,我已经用 sn-p 编辑了我的帖子

标签: javascript css tabs panel


【解决方案1】:

您可能会发现此代码修订版中的一些想法很有用。


需要注意的主要变化包括:

  • 此版本不是内联事件处理程序,而是在按钮的父 div 上使用单个事件侦听器(这是因为 DOM 事件通常会冒泡到祖先元素)。
  • 关于修改哪个元素的决定使用事件的target属性加上每个按钮上的数据属性(告诉监听器哪个选项卡与该按钮相关联)。
  • HTML 包含两个新类(CSS 中的选择器将其定位):hiddenhighlight。该脚本会根据需要添加或删除这些类,而不是手动操作样式。

这些更改有助于页面上的关注点分离(标记、样式和脚本),并允许减少重复代码,这两者都可以使您的代码不易出错且更易于维护。


"tabgroup" div 动态调整大小以适应其内容,如您所料,无需通过显式样式更改其高度。

请参阅代码内的 cmets 以获得进一步的解释(并注意一些原始 HTML 和 CSS 已被更改或省略,以简洁明了。)

// Identifies some DOM elements
const
  buttonGroup = document.getElementsByClassName("tabbuttongroup")[0],
  buttons = document.getElementsByClassName("tabbutton");
  tabs = document.querySelectorAll(".tabgroup .tabcontent");

// Calls `updateTabsDisplay` when user clicks inside buttonGroup
buttonGroup.addEventListener("click", updateTabsDisplay);

// Defines listener (which always has access to the triggering event)
function updateTabsDisplay(event){
  const clicked = event.target; // Event's `target` property is useful

  // Ignores irrelevant clicks
  if(!clicked.classList.contains("tabbutton")){ return; }

  // Un-highlights buttons, and highlights clicked button
  for(let button of buttons){
    button.classList.remove("highlight");
    if(button == clicked){
      clicked.classList.add("highlight");
    }
  }

  // Reads button's `data-tab` attribute, where associated tabClass is stored
  const tabClass = clicked.dataset.tab;

  // Hides tabs, and un-hides the matching tab
  for(let tab of tabs){
    tab.classList.add("hidden");
    if(tab.classList.contains(tabClass)){
      tab.classList.remove("hidden");
    }
  }
}
.tabbutton { background-color: rgba(55,175,75,1.00); color: white; padding: 8px; float: left; width: 12ch; text-align: center; }
.tabbutton + .tabbutton { border-left: 1px solid white; }
.tabbutton:hover { background-color: rgba(55,175,75,0.80); }
.tabbutton.highlight { background-color: rgba(55,175,75,0.50); }

.tabgroup { clear: both; }
.tabcontent { padding: 0 0 8px 0; }

.hidden{ display: none; } 
<div class="tabbuttongroup">
  <!-- `data-attributes` can be used to store relevant strings -->
  <div class="tabbutton highlight" data-tab="tab-calendar">Calendar</div>
  <div class="tabbutton" data-tab="tab-pruning">Pruning</div>
  <div class="tabbutton" data-tab="tab-pregrow">Pregrow</div>
  <div class="tabbutton" data-tab="tab-aftergrow">Aftergrow</div>
  <div class="tabbutton" data-tab="tab-neighbour">Neighbour</div>
</div>

<div class="tabgroup">
  <!-- Each tab has a class matching its button's `data-tab` attribute -->
  <div class="tabcontent tab-calendar">
    <p>"Calendar Tab" content<br/>..<br/>..<br/>..<hr></p>
  </div>
  <div class="tabcontent tab-pruning hidden">
    <p>"Pruning Tab" content<hr></p>
  </div>
  <div class="tabcontent tab-pregrow hidden">
    <p>"Pregrow Tab" content<br/>..<br/>..<br/>..<br/>..<br/>..<br/>..<hr></p>
  </div>
  <div class="tabcontent tab-aftergrow hidden">
    <p>"Aftergrow Tab" content<br/>..<br/>..<br/>..<br/>..<hr></p>
  </div>
  <div class="tabcontent tab-neighbour hidden">
    <p>"Neighbour Tab" content<hr></p>
  </div>
</div>

【讨论】:

  • 感谢您的回复。虽然这非常有用并且我已经实现了这一点,但真正的问题是父级(可折叠面板)在不同大小的选项卡之间切换时没有调整大小。
  • 啊。我终于注意到每个.calendar-fold 元素上的听众设置下一个.calendar-unfold 元素的高度——我最初错过了,并认为尽管没有内容,但它正在设置自己的高度,所以我错误地忽略了它。对于那个很抱歉。无论如何,你能说哪个元素是“父(折叠面板)”吗?也许你还可以指出active 类应该有什么效果(如果有的话)? b>
  • 哎呀,我忘了在sn-p中添加活动类。愚蠢的我......我已经编辑了我的原始帖子 sn-p 也包含 CSS 中的活动类
  • 太好了,哪个元素是应该调整大小的“父(折叠面板)”?和.calendar-unfold元素一样吗?
  • 当单击“.calendar-fold”元素时,“.calendar-unfold”元素应该展开和折叠。我不知道为什么 CSS 过渡在这里停止工作。并且在子标签之间切换时,父“.calendar-unfold”元素应根据标签的高度调整大小。
猜你喜欢
  • 2013-04-07
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-24
  • 1970-01-01
  • 2015-11-25
相关资源
最近更新 更多