Как создавать элементы HTML-аккордеона с использованием JavaScript и без него
Элементы аккордеона очень удобны для отображения заголовков тем и расширяемых под ними деталей при нажатии на заголовок.
В этой статье я расскажу вам, как создать раздел часто задаваемых вопросов с некоторыми расширяемыми элементами-аккордеонами.
Я покажу вам, как это сделать без использования JavaScript, а затем мы добавим немного JavaScript, чтобы сделать его еще лучше.
Как сделать аккордеон, используя details
В HTML есть элемент раскрытия <details>
, который может находиться в одном из двух состояний: открытом и закрытом. При открытии отображается информация внутри элемента. В закрытом виде отображается только <summary>
информация.
Это чрезвычайно простая версия аккордеона, хотя, возможно, сама по себе она не является настоящей. При использовании <details>
одновременно может быть открыто несколько панелей, а поскольку JavaScript еще отсутствует, панели будут оставаться открытыми до тех пор, пока вы не щелкните их еще раз, чтобы закрыть.
Тем не менее, это быстрый и простой способ запустить элемент, похожий на гармошку. Если вам нужно всего несколько штук и вы не требовательны к функциональности, возможно, это все, что вам нужно.
Вот как выглядит базовый пример. Значок <summary>
виден до тех пор, пока не будет щелкнут по нему, после чего под ним отобразится остальная часть содержимого.
<!-- With just <details> -->
<section>
<h2>Accordion using details</h2>
<details open>
<summary>Who is Eamonn?</summary>
A guy from TN who makes content on the internet.
</details>
<details>
<summary>What kind of content does he make?</summary>
He focuses on productivity tips using coding and spreadsheets. He makes <a href="https://youtube.com/@eamonncottrell">YouTube</a> videos and writes articles on freeCodeCamp, <a href="https://www.linkedin.com/in/eamonncottrell/">LinkedIn</a> and his <a href="https://got-sheet.beehiiv.com/">personal newsletter</a>.
</details>
<details>
<summary>What does he do for fun?</summary>
Hangs out with his wife and four kids, and runs ultramarathons.
</details>
</section>
Мы также можем открыть первую панель сведений по умолчанию, просто включив команду open: <details open>
.
Вот как это будет выглядеть, если добавить немного CSS:
Это отличное начало, но мы можем пойти дальше. Немного JavaScript будет иметь большое значение.
Как добавить JavaScript в элемент аккордеона
Давайте сделаем еще один раздел с еще тремя <details>
элементами. И давайте добавим class = "withJS"
к каждому из них, чтобы мы могли делать с ними разные вещи для сравнения.
<!-- With JavaScript -->
<section>
<h2>Accordion with some JavaScript added</h2>
<details open>
<summary class="withJS">What's the difference?</summary>
We're adding JavaScript to these three.
</details>
<details >
<summary class="withJS">Why add JavaScript?</summary>
We can make it so only one panel can be open at a time.
</details>
<details >
<summary class="withJS">Try clicking each of these</summary>
See how one closes as soon as the other opens?.
</details>
</section>
Чтобы все было в порядке и в одном файле, мы можем добавить тег <script>
внизу нашего <body>
Сначала выберите все элементы сводки с .withJS
классом, используя document.querySelectorAll()
:
const summaries = document.querySelectorAll(".withJS")
Затем добавьте прослушиватель событий кликов к каждому из них:
summaries.forEach(e=>{
e.addEventListener('click',openCloseDetails)
})
Функция будет запускаться openCloseDetails
каждый раз при щелчке по одному из этих элементов сводки. Однако она ничего не сделает, кроме как выдаст нам ошибку, пока мы не объявим эту функцию... так что давайте сделаем это дальше.
В <script>
после цикла forEach
давайте снова запустим функцию openCloseDetails()
для повторного просмотра этих сводок. На этот раз мы хотим изменить статус open
для элемента <details>
.
Нам нужен способ переключить выбранный элемент из открытого в закрытый и закрыть любой предыдущий open
элемент, когда мы щелкаем новый.
Чтобы сделать это, мы установим переменную для элемента <details>
каждого из элементов <summary>
, установив ее равной e.parentNode
в цикле forEach
.
let details = e.parentNode;
parentNode
- это элемент, непосредственно предшествующий текущему элементу. Поскольку элементы <summary>
находятся внутри элементов <details>
, родительским узлом для элементов <summary>
будет <details>
.
Оттуда мы проверяем, не является ли этот <details>
this.parentNode
. Если это не так, то мы удалим атрибут open
.
Встроенная функциональность элементов <details>
откроет тот, на который был сделан щелчок, нам просто нужно было убедиться, что все остальные закрыты.
Вот код. Это несложно, но может потребоваться секунда, чтобы понять логику:
summaries.forEach(e =>{
let details = e.parentNode;
if(details != this.parentNode){
details.removeAttribute('open')
}
И это все. Теперь, когда мы нажимаем на каждый <details>
, остальные автоматически закрываются:
Вот весь HTML-файл для справки:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accordion</title>
</head>
<body>
<style>
body{
background: rgb(255, 255, 230);
color: #444;
}
details{
font-family:'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
margin-bottom: 5px;
padding: 0.5em 0.5em 0;
}
details[open]{
padding: 0.5em;
}
summary{
font-weight: bold;
margin: -0.5em -0.5em 0;
padding: 0.5em;
cursor: pointer;
}
details[open] summary{
margin-bottom: 0.5em;
}
</style>
<h1>Accordions</h1>
<!-- With just <details> -->
<section>
<h2>Accordion using details</h2>
<details open>
<summary>Who is Eamonn?</summary>
A guy from TN who makes content on the internet.
</details>
<details>
<summary>What kind of content does he make?</summary>
He focuses on productivity tips using coding and spreadsheets. He makes <a href="https://youtube.com/@eamonncottrell">YouTube</a> videos and writes articles on freeCodeCamp, <a href="https://www.linkedin.com/in/eamonncottrell/">LinkedIn</a> and his <a href="https://got-sheet.beehiiv.com/">personal newsletter</a>.
</details>
<details>
<summary>What does he do for fun?</summary>
Hangs out with his wife and four kids, and runs ultramarathons.
</details>
</section>
<!-- With JavaScript -->
<section>
<h2>Accordion with some JavaScript added</h2>
<details open>
<summary class="withJS">What's the difference?</summary>
We're adding JavaScript to these three.
</details>
<details >
<summary class="withJS">Why add JavaScript?</summary>
We can make it so only one panel can be open at a time.
</details>
<details >
<summary class="withJS">Try clicking each of these</summary>
See how one closes as soon as the other opens?.
</details>
</section>
<script>
const summaries = document.querySelectorAll(`.withJS`)
summaries.forEach(e=>{
e.addEventListener('click',openCloseDetails)
})
function openCloseDetails(){
summaries.forEach(e =>{
let details = e.parentNode;
if(details != this.parentNode){
details.removeAttribute('open')
}
})
}
</script>
</body>
</html>