Vanilla JavaScript 手风琴功能
我需要帮助,以便在单击打开其他面板后关闭其他面板。过去一周我一直在努力解决这个问题,但就是做不到。
我不想使用 jquery 库,我希望能够将此代码直接编码到我的网站中。
我认为所需的 javascript 代码在概念上很简单,但对于像我这样的人来说很难编写。我仍然不完全了解 javascript 命令、函数等的工作原理。
任何帮助或指导都将不胜感激!
这是我的代码:
HTML
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="accordion.css">
</head>
<body>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
<script src="accordion.js"></script>
</body>
</html>
CSS
.accordion {
background-color: #2364aa;
color: #ffffff;
cursor: pointer;
padding: 18px;
border: none;
text-align: left;
outline: none;
font-size: 21px;
transition: 0.4s;
}
.open, .accordion:hover {
background-color: #205A99;
}
.accordion:after {
content: '\f067';
font-family: "Font Awesome 5 Free";
color: #ffffff;
float: right;
font-size: 1.25em;
line-height: 25px;
}
.open:after {
content: "\2212";
}
.panel {
max-height: 0;
overflow: hidden;
transition: 0.2s ease-out;
}
.panel-body {
padding: 18px 0;
}
@media only screen and (min-width: 960px) {
.container {
display: table;
box-sizing: border-box;
}
.row .col {
margin: 10px 0;
}
.col {
display: table-cell;
}
.col.middle {
vertical-align: middle;
}
.col-2 {
width: 50%;
padding-right: 72px;
}
.col-4 {
width: 33.33333333333333333%;
padding-right: 72px;
}
}
Javascript
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
事件委托
-
将所有内容包装在块元素中。
var main = document.querySelector(`main`)
-
向该“父”元素添加 EventListener
main.addEventListener('click', ....
-
现在,如果单击
main
或main
的任何后代,则会调用回调函数。因此,我们只有一个 EventListener 代表每个.accordion
监听单击事件。我们使用if
条件和event.target
来确定实际单击了哪个.accordion
属性。 -
相互排斥 规则适用于手风琴的工作方式:
-
只有一个
.accordion + .panel
组合可以具有.active
类。 -
每当需要更改时(在本例中,
e.target
(被点击的元素)已被点击), 所有.accordion
都将删除.active
类(无论它们是否实际拥有该类)。 -
在没有元素具有
.active
类之后,您将其提供给e.target
。
-
变化
-
.accordion + .panel.active
代替.accordion.active
。 -
.style.maxHeight
被.active
类取代:.panel.active { max-height: 2000px; height:auto; overflow: hidden; transition: 0.2s ease-out; }
Demo
详细信息在 Demo 中有注释
// Reference the parent of all .accordion
var main = document.querySelector('main');
/* Register main to click events...
|| when main or any of its descendant elements are clicked...
*/
main.addEventListener("click", function(e) {
/* Collect all .accordion into a NodeList and convert it into
|| an array.
*/
var acc = Array.from(document.querySelectorAll(".accordion"));
/* Loop thru each .accordion to remove the .active class
|| from each .panel
*/
for (let a = 0; a < acc.length; a++) {
var panel = acc[a].nextElementSibling;
panel.classList.remove('active');
}
/* After nothing has class .active, assign .active to the
|| .panel of the clicked element (e.target)
*/
if (e.target !== e.currentTarget) {
var tgt = e.target.nextElementSibling;
tgt.classList.add("active");
}
});
.accordion {
background-color: #2364aa;
color: #ffffff;
cursor: pointer;
padding: 18px;
border: none;
text-align: left;
outline: none;
font-size: 21px;
transition: 0.4s;
}
.open,
.accordion:hover {
background-color: #205A99;
}
.accordion:after {
content: '\f067';
font-family: "Font Awesome 5 Free";
color: #ffffff;
float: right;
font-size: 1.25em;
line-height: 25px;
}
.open:after {
content: "\2212";
}
.panel {
max-height: 0;
overflow: hidden;
transition: 0.2s ease-out;
}
.panel.active {
max-height: 2000px;
height:auto;
overflow: hidden;
transition: 0.2s ease-out;
}
@media only screen and (min-width: 960px) {
.container {
display: table;
box-sizing: border-box;
}
.row .col {
margin: 10px 0;
}
.col {
display: table-cell;
}
.col.middle {
vertical-align: middle;
}
.col-2 {
width: 50%;
padding-right: 72px;
}
.col-4 {
width: 33.33333333333333333%;
padding-right: 72px;
}
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<main>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
</main>
</body>
</html>
希望此功能对您有所帮助
function closeAll() {
var accs = document.querySelectorAll('.accordion');
for(var i = 0; i < accs.length; i ++) {
accs[i].classList.remove('active');
var panel = accs[i].nextElementSibling;
panel.style.maxHeight = null;
}
}
更新
我们可以通过将这个条件添加到
closeAll
函数来跳过关闭点击元素:
if (accs[i] == tar) {
continue;
}
完整代码在这里
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function(ev) {
closeAll(ev.target);
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
function closeAll(tar) {
var accs = document.querySelectorAll('.accordion');
for (var i = 0; i < accs.length; i++) {
if (accs[i] == tar) {
continue;
}
accs[i].classList.remove('active');
var panel = accs[i].nextElementSibling;
panel.style.maxHeight = null;
}
}
.accordion {
background-color: #2364aa;
color: #ffffff;
cursor: pointer;
padding: 18px;
border: none;
text-align: left;
outline: none;
font-size: 21px;
transition: 0.4s;
}
.open,
.accordion:hover {
background-color: #205A99;
}
.accordion:after {
content: '\f067';
font-family: "Font Awesome 5 Free";
color: #ffffff;
float: right;
font-size: 1.25em;
line-height: 25px;
}
.open:after {
content: "\2212";
}
.panel {
max-height: 0;
overflow: hidden;
transition: 0.2s ease-out;
}
.panel-body {
padding: 18px 0;
}
@media only screen and (min-width: 960px) {
.container {
display: table;
box-sizing: border-box;
}
.row .col {
margin: 10px 0;
}
.col {
display: table-cell;
}
.col.middle {
vertical-align: middle;
}
.col-2 {
width: 50%;
padding-right: 72px;
}
.col-4 {
width: 33.33333333333333333%;
padding-right: 72px;
}
}
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="accordion.css">
</head>
<body>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
<h3 class="accordion">Basics of Sailing</h3>
<div class="panel">
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Before Choosing a Sailboat</h4>
<p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Car Topping & Trailing</h4>
<p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
</div>
<div class="col col-4 middle">
<!-- <div class="space"></div> -->
<h4>Safety Equipment</h4>
<p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
</div>
</div>
<script src="accordion.js"></script>
</body>
</html>
这是 Vanilla js 中名为 Accordion 的类。它主要展示 javascript 中的功能,样式不太好 :)
class Accordion {
constructor(AccordionData) {
// State
this.data = AccordionData;
// View Layer
this.mainContainer = document.querySelector('.container');
this.allAccordionDetailsElements = [];
this.init();
}
init() {
this.createAccordions();
this.bindEvents();
}
createAccordions() {
this.data.forEach(acc => {
let accordionHTML = this.generateHTML(acc);
this.mainContainer.appendChild(accordionHTML);
});
this.allAccordionDetailsElements = document.querySelectorAll('.accordion-details');
}
checkIfCurrentTarget(targetEl, detailsEl) {
return detailsEl.dataset.target === targetEl.id;
}
getDisplayStatus(element) {
return element.style.display;
}
toggleDetailsVisibility(detailsEl) {
const isVisible = this.getDisplayStatus(detailsEl) === 'block';
if (!isVisible) {
detailsEl.style.display = 'block';
} else {
detailsEl.style.display = 'none';
}
}
hideAllDetails() {
this.allAccordionDetailsElements.forEach(detailsSection => {
detailsSection.style.display = 'none';
});
}
bindEvents() {
this.mainContainer.addEventListener('click', (e) => {
if (typeof e === 'undefined') return;
const targetEl = e.target;
const isAccordionHeader = targetEl.classList.contains('accordion-header');
if (isAccordionHeader) {
this.hideAllDetails();
this.allAccordionDetailsElements.forEach(detailsSection => {
if (this.checkIfCurrentTarget(targetEl, detailsSection)) {
this.toggleDetailsVisibility(detailsSection)
}
});
}
});
}
generateHTML(accordionElData) {
const { id, headerText, detailsText } = accordionElData;
const sectionEl = document.createElement('section');
sectionEl.className = 'accordion-container';
const headerEl = document.createElement('button');
headerEl.type = 'button';
headerEl.className = 'accordion-header';
headerEl.textContent = headerText;
headerEl.id = id;
const articleEl = document.createElement('article');
articleEl.className = 'accordion-details';
articleEl.textContent = detailsText;
articleEl.dataset.target = id;
sectionEl.appendChild(headerEl);
sectionEl.appendChild(articleEl);
return sectionEl;
}
}
const AccordionData = [
{
id: 'acc-1',
headerText: 'Section 1',
detailsText: 'This is dummy Text for Section 1'
},
{
id: 'acc-2',
headerText: 'Section 2',
detailsText: 'This is dummy Text for Section 2'
},
{
id: 'acc-3',
headerText: 'Section 3',
detailsText: 'This is dummy Text for Section 3'
}
];
window.addEventListener('DOMContentLoaded', () => {
const accordion = new Accordion(AccordionData);
});
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.accordion-details {
display: none;
}
<main class="container"></main>