Я хотел бы сделать 3 кнопки, каждая из которых делает весь контент div display: none
, и в зависимости от кнопки, которую вы нажали, один из элементов контента изменится на display: block
. Например, если я нажму на вторую кнопку, будет показано только второе содержимое div.
function showPanel(id) {
var elements = document.getElementsByClassName("content");
for (let i = 0; i < elements.length; i++) {
document.getElementById(i).style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<div class="content">
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>
5 ответов
Множественные проблемы.
- Длина может быть рассчитана с использованием
elements.length
, а неelements.length()
. - Вы дали одно и то же имя класса как родительскому, так и дочернему div. Таким образом, скрытие всех элементов с именем класса
content
скроет всех ваших родителей. Поэтому после обновленияstyle.display = "block"
до требуемой цели это не сработает. Потому что ваш родитель ужеstyle.display = "none"
. Таким образом, вы должны сделать обновление логики там. Поэтому я изменил имя родительского класса.
function showPanel(id) {
var elements = document.getElementsByClassName("content");
for (let i = 0; i < elements.length; i++) {
elements[i].style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<div>
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>
В вашем коде есть пара проблем. Во-первых, length
— это свойство, а не метод, поэтому вам не нужен суффикс ()
для его вызова. Во-вторых, в HTML нет атрибута className
. Это должно быть просто class
. Наконец, родительский контейнер имеет тот же класс, что и скрываемые элементы, поэтому все дочерние элементы будут скрыты, даже если к ним применено display: block
.
После исправления этих проблем ваш код будет выглядеть так:
function showPanel(id) {
var elements = document.getElementsByClassName("panel");
for (let i = 0; i < elements.length; i++) {
elements[i].style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('p1')">test1</button>
<button onclick="showPanel('p2')">test2</button>
<button onclick="showPanel('p3')">test3</button>
<div class="content">
<div id="p1" class="panel">
<p>TEST1</p>
</div>
<div id="p2" class="panel">
<p class="other">TEST2</p>
</div>
<div id="p3" class="panel">
<p class="other">TEST3</p>
</div>
</div>
Однако стоит отметить, что использование атрибутов onX
устарело и не является хорошей практикой. Лучшим решением было бы использовать ненавязчивые обработчики событий и предоставлять настраиваемые метаданные обработчику событий через атрибуты data
, размещенные на элементах.
Улучшенная версия логики будет выглядеть так:
let buttons = document.querySelectorAll('button');
let panels = document.querySelectorAll('.panel');
buttons.forEach(button => {
button.addEventListener('click', e => {
panels.forEach(panel => {
panel.style.display = panel.id === e.target.dataset.panel ? 'block' : 'none';
});
});
});
<button data-panel="1">test1</button>
<button data-panel="2">test2</button>
<button data-panel="3">test3</button>
<div class="content">
<div id="1" class="panel">
<p>TEST1</p>
</div>
<div id="2" class="panel">
<p class="other">TEST2</p>
</div>
<div id="3" class="panel">
<p class="other">TEST3</p>
</div>
</div>
Нет необходимости в JS или Jquery. Вместо кнопки можно использовать тег привязки. Затем вы вызываете с помощью привязки идентификатор элемента. И последнее, но не менее важное: вы делаете поля скрытыми с помощью CSS и используете селектор :target
для отображения элементов:
.content {
display: none;
}
.content:target {
display: block;
}
<a href="#1">test1</a><br>
<a href="#2">test2</a><br>
<a href="#3">test3</a><br>
<div class="content-container">
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>
:target
, так как это предотвратит указанную вами проблему.
Более элегантный способ, которым я мог бы подойти к проблеме, подобной этой, состоял бы в том, чтобы связать панели и их триггеры вместе, используя атрибуты данных. Таким образом, вы не рискуете конфликтовать с другими идентификаторами, которые могут совпадать на странице (идентификаторы всегда должны быть уникальными).
Перед настройкой прослушивателя событий я бы инициализировал переменную openPanel
и установил ее для любой панели, которая уже создана с именем класса active
. Всякий раз, когда мы открываем новую панель, мы перезаписываем эту переменную vaklue, поэтому нам не нужно каждый раз делать новую querySelctor
.
Затем в CSS вместо того, чтобы скрывать все панели, а затем показывать одну с активным классом, мы можем написать единый стиль, который скрывает все панели без активного класса, используя метод :not
селектор отрицания.
Вот как это будет выглядеть (инициализация с открытой панелью №1 по умолчанию, но вы можете просто удалить из нее активный класс в HTML, если вы этого не хотите):
let openPanel = document.querySelector('[data-panel-id].active');
document.addEventListener('click', e => {
if (e.target?.matches?.('[data-panel-target]')) {
const id = e.target.dataset.panelTarget;
if (id) {
const panel = document.querySelector(`[data-panel-id="${id}"]`);
if (panel) {
openPanel?.classList.remove('active');
panel.classList.add('active');
openPanel = panel;
}
}
}
})
[data-panel-id]:not(.active) {
display: none;
}
<button data-panel-target="1">test1</button>
<button data-panel-target="2">test2</button>
<button data-panel-target="3">test3</button>
<main>
<div data-panel-id="1" class="active">
<p>TEST #1</p>
</div>
<div data-panel-id="2">
<p>TEST #2</p>
</div>
<div data-panel-id="3">
<p>TEST #3</p>
</div>
</main>
Я уже отправил отдельное решение с моей предпочтительной рекомендацией, но я хотел дать ответ на ваш вопрос, используя тот же подход, с которого вы начали, чтобы не отклоняться от кода, который у вас уже есть.
Код, который у вас уже был, на самом деле уже был близок к тому, чтобы работать. Основная проблема, которую я увидел, заключалась в том, что вы использовали document.getElementById(i)
там, где на самом деле должны были использовать elements[i]
. Однако мы можем улучшить это, заменив цикл for циклом for..of и определив встроенно, является ли текущий оцениваемый элемент тем, который мы хотим показать. Если это так, мы используем 'block'
, иначе 'none'
.
После инициализации нашей функции мы можем вызвать ее для одного из наших идентификаторов в JS, чтобы по умолчанию была открыта одна панель. ** Также важно, чтобы родитель всех этих элементов .content
НЕ содержал имя класса content
, так как это может конфликтовать с вашей функцией. Я заменил этот родительский элемент простым элементом <main>…</main>
.
Вот как я могу решить эту проблему, используя ваш существующий подход:
function showPanel(contentId) {
const elements = Array.from(document.getElementsByClassName('content'));
for (const element of elements) {
element.style.display = element.id === contentId ? 'block' : 'none';
}
}
showPanel('1');
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<main>
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p>TEST2</p>
</div>
<div id="3" class="content ">
<p>TEST3</p>
</div>
</main>
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.
elements.length()
— это не функция, это свойство. Попробуйте вместо этого использовать .length!