当前行为
我有以下的基本结构:
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content">Content</div>
</div>
<!-- ... dozens of .boxes ... -->
</section>
#containers
是.display: flex; flex-wrap: wrap
,因此任意一行上的框数是动态的。这是一个必须维护的重要特性。
下面是一个最小的工作示例:
$(document).ready(function() {
$(".collapsible").click(function() {
$( this ).next().slideToggle();
});
});
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
.collapsible:hover {
background: #aaf;
}
.content {
margin: 0.5em;
margin-left: 16px;
display: none; /* Initially collapsed */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box3">
<div class="collapsible"><h2>Box 3</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box4">
<div class="collapsible"><h2>Box 4</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box5">
<div class="collapsible"><h2>Box 5</h2></div>
<div class="content">Content</div>
</div>
</section>
</body>
我可以很容易地使用.slideToggle()
来切换兄弟姐妹(.content
)的可见性,在一个可点击的.collapsible
div下面:
$(".collapsible").click(function() {
$( this ).next().slideToggle();
});
期望行为与备注
我想要的是,点击任何.collapsible
div在一行中,整个行将被切换。也就是说,每个.content
div都位于与当前视窗显示的相同的水平行上。
这必须处理具有动态列数的行,包括视口调整大小。不过,我对具体的行为是灵活的。
这可能吗?会有多痛?🙂更改文档结构(例如添加某种类型的行容器)是可以的,当然,我不介意使用一些JS/jQuery代码。我不能做的主要事情是硬编码列的数量,因为我需要我的网站在垂直手机和全屏桌面浏览器上保持响应。
也许jQuery的slideToggle()
函数不是最好的方法。
由于每一行的高度相同,您可以查看将大小从0设置为另一个值的方法。任何调整大小的盒子都会拉伸同一行的其他盒子。
在这里的想法的一个例子,设置最大高度从0到200px和过渡。它可以切换一个类。
$(document).ready(function() {
$(".collapsible").click(function() {
this.classList.toggle('slide');// plain javascript to toggle a class
});
});
*{box-sizing:border-box}
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
p{margin-top:0;}
.collapsible:hover {
background: #aaf;
}
.content {
margin:0 0.5em;
margin-left: 16px;
max-height:0; /* Initially collapsed */
transition:0.5s
}
.slide + .content{max-height:400px;/* which one got the class*/ color:darkred}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content"><p>Content</p></div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content"><p>Content</p><p>Content</p></div>
</div>
<div class="box" id="box3">
<div class="collapsible"><h2>Box 3</h2></div>
<div class="content"><p>Content</p></div>
</div>
<div class="box" id="box4">
<div class="collapsible"><h2>Box 4</h2></div>
<div class="content"><p>Content</p><p>Content</p><p>Content</p></div>
</div>
<div class="box" id="box5">
<div class="collapsible"><h2>Box 5</h2></div>
<div class="content"><p>Content</p></div>
</div>
</section>
</body>
您在这里缺少的是将行高度设置为较高框的高度,除非它们的高度相同。
对于这个,您可以查找每个框在相同的顶部偏移量的点击,并查找最高的内部内容。contents并使用这个高度。
看看每个人站在哪里并重置最大高度规则,你也可以从中获得灵感:
// defaut : supposed to be with no class 'slide' set on html elements
$(document).ready(function () {
let boxes = document.querySelectorAll(".collapsible");
let contents = document.querySelectorAll(".content");
$(".collapsible").click(function (event) {
let arrayContent = [];//reset
let hide=false;
for (i = 0; i < contents.length; i++) {
contents[i].style.maxHeight = "min-content";
let index = i;
let heightC = contents[i].offsetTop;
let boxOffset = contents[i].parentNode.offsetTop + 1;
// a few infos .add/remove what is needed
arrayContent.push({
index,
heightC,
boxOffset
});
contents[i].setAttribute("style", "");// resets inline style
}
let rowOffset = this.offsetTop;
if(this.classList.contains('slide')) {
hide=true;
}
let classState = this.classList;
arrayContent.forEach(function (obj) {
if (obj.boxOffset == rowOffset) {
if(hide == true) boxes[obj.index].classList.add('slide');/* reset needed if window resized => rows reorganized ? */
boxes[obj.index].classList.toggle("slide");
} else {
boxes[obj.index].classList.remove("slide");
}
});
});
});
* {
box-sizing: border-box
}
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
p {
margin-top: 0;
}
.collapsible:hover {
background: #aaf;
}
.content {
margin: 0 0.5em;
margin-left: 16px;
max-height: 0;
/* Initially collapsed */
transition: max-height 0.5s!important
}
.slide~.content {
max-height: 400px;
/* which one got the class*/
color: darkred;
}
.collapsible:before {
content: attr(class)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible">
<h2>Box 1</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
<div class="box" id="box2">
<div class="collapsible">
<h2>Box 2</h2>
</div>
<div class="content">
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="box" id="box3">
<div class="collapsible">
<h2>Box 3</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
<div class="box" id="box4">
<div class="collapsible">
<h2>Box 4</h2>
</div>
<div class="content">
<p>Content</p>
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="box" id="box5">
<div class="collapsible">
<h2>Box 5</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
</section>
</body>