Я использую следующую кодовую форму w3schools, которая использует кнопку для переключения текста:
function myFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}<button onclick = "myFunction()">Try it</button>
<div id = "myDIV">
This is my DIV element.
</div>Теперь я хочу иметь страницу с множеством кнопок, которые переключают разные тексты (каждая кнопка соответствует уникальному тексту). Конечно, я могу заставить его работать, копируя функцию каждый раз, когда создаю новый текст; myFunction1 <-> myDIV1, myFunction2 <-> myDIV2 и т. д.
Но есть ли более разумный способ сделать это? Я думаю, что это можно сделать с помощью одной функции, которая выбирает идентификаторы в определенной форме, но я не знаю, как это сделать.
Или используйте event.target.id
вы можете создать функцию переключения и передать идентификатор в качестве аргумента, поэтому каждый раз, когда вы нажимаете на любую кнопку, она будет вызывать вашу функцию с переданным вами идентификатором - ``` <button onclick = "toggleText('myDIV1')"> Переключить текст 1</button> <div id = "myDIV1"> Это текст 1. </div> <script> function toggleText(targetId) { var x = document.getElementById(targetId); if (x.style.display === "none") { x.style.display = "block"; } еще { x.style.display = "нет"; } } </script>```
Каждая кнопка сгруппирована вместе с текстом, который она предназначена для переключения? Или они находятся на отдельных частях страницы? Вам могут не понадобиться идентификаторы, если они сгруппированы.
«Есть ли более разумный способ сделать это» — вы можете передать идентификатор функции или использовать атрибут data- на кнопке, которая указывает на идентификатор. Но «умнее» субъективно, и здесь, в Stack Overflow, мы предпочитаем объективные вопросы.
@ 0stone0 Они не хотят работать с тем же элементом, на который нажали. Они нажимают на кнопку, она меняет стиль div.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Поскольку вы изучаете JavaScript, я предлагаю научиться не использовать некоторые традиционно вредные привычки.
Одна вещь, которая обычно доставляет больше хлопот, чем она того стоит, — это встроенные обработчики кликов. Значение onclick='myfunction()' на ваших элементах. Вместо этого использование addEventListener предлагает больше возможностей.
Кроме того, еще одна интересная вещь, которую стоит изучить, — это переключение класса CSS для ваших элементов вместо изменения стиля непосредственно в JavaScript.
Поэтому для своего ответа я фактически добавляю обработчик кликов в тело. Затем, когда вы нажимаете, я проверяю, имеет ли элемент, на который вы нажали, определенный класс. Я дал вашим кнопкам класс btnToggle.
Затем для каждой кнопки я использую атрибуты данных, чтобы указать, на что должна быть нацелена эта кнопка. Это делается с помощью data-target = "#divID".
Теперь в обработчике кликов я получаю эту цель, получая щелкнутый элемент и data.target.
Теперь я использую класс CSS под названием active, который настраивает отображение на отображение.
Затем я просто использую список классов выбранного элемента для переключения этого класса.
document.body.addEventListener("click",(e) => {
const el = e.target;
if (el.classList.contains("btnToggle")){
const targetDiv = document.querySelector(el.dataset.target)
targetDiv.classList.toggle("active")
}
});.contentDiv{display:none}
.active{
display:block
}<button data-target = "#myDIV1" class = "btnToggle">Try it 1</button>
<div id = "myDIV1" class = "contentDiv">
This is my DIV element. 1
</div>
<button data-target = "#myDIV2" class = "btnToggle">Try it 2</button>
<div id = "myDIV2" class = "contentDiv">
This is my DIV element. 2
</div>Вы могли бы упростить это немного. Вместо того, чтобы использовать атрибуты ID и данных, вы можете просто сделать -> const targetDiv = el.nextElementSibling;
@Keith Да, есть способы упростить. Я намеренно не использовал nextElementSibling, так как предполагается, что div находится сразу после кнопки. Таким образом, это заставляет OP следовать определенному макету.
Да, справедливое замечание. Но с положительной стороны, используя nextElementSibling, ОП может просто скопировать и вставить, и ему не нужно беспокоиться об идентификаторах.
Хотя этот код работает, использование атрибутов data-* для хранения идентификатора, используемого в качестве целевой ссылки, не масштабируется. Идентификаторов следует полностью избегать, когда это возможно (что бывает в большинстве случаев). Кроме того, использование делегирования событий является хорошим подходом, но настройка обработчика на body также не является лучшей практикой, поскольку (в зависимости от глубины DOM) событие должно всплывать выше, чем хотелось бы, из-за конфликтов с другие click события.
Что касается вашего комментария о том, что код OP должен следовать определенному макету, это не обязательно плохо, поскольку он добавляет согласованности коду и (как указано) позволяет полностью удалить идентификаторы. Это очень распространенная практика.
Во-первых, позвольте мне сказать, что хорошо известно, что W3Schools предоставляет неполную, устаревшую или просто неправильную информацию. Вы должны держаться как можно дальше от него как от учебного ресурса. Вместо этого Сеть разработчиков Mozilla (которые являются распорядителями языка JavaScript) имеет то, что считается авторитетным источником для обучения и документации по многим веб-технологиям и языкам.
Что касается вашего вопроса (и поскольку вы получили код от W3Schools), мы должны немного подкрепиться.
style
обескураженный. Это вызывает добавление так называемого встроенного стиля.
к элементному и встроенному стилям приводят к дублированию кода и
трудности с переопределением этих стилей, когда это неизменно необходимо.id на элементах — очень простой способ доступа к частям.
вашей страницы и работать с ними, но это также не рекомендуется, потому что
id Скрипты на основе id приводят к хрупкому коду, который плохо масштабируется.
Также следует избегать использования id в пользу других способов
(т. е. расположение элемента по отношению к другим элементам).С учетом всего сказанного, лучшим подходом здесь было бы нажимать несколько кнопок, но чтобы каждая из них просто заполняла один общий элемент вывода при нажатии. Таким образом, вам не нужно знать ни о каких style.
См. встроенные комментарии ниже:
// Get your element references you'll need just once,
// rather than each time the function is called.
// And note here that we can get the reference by
// searching for the first instance of an element
// that matches the specified class.
const output = document.querySelector(".output");
// Set up events for your elements in JavaScript, not HTML
// Here, we'll set up a click event handler for the parent
// of the 3 sample buttons. When any button gets clicked,
// the click event will "bubble" up to the parent and be
// handeled there. This is called "event delegation".
document.querySelector(".wrapper").addEventListener("click", myFunction);
function myFunction(event) {
// Check to see if the event was triggered
// by an element we care to handle
if (event.target.classList.contains("topic")){
// Update the status of the element
event.target.closest("label").classList.toggle("active");
// Check to see which button was clicked so we know which text to display
if (event.target.classList.contains("a")){
// This is called a "ternary operator" and works like this:
// some value = condition ? value if condition is true : value if false
output.textContent = output.textContent === "" ? "TOPIC A" : "";
} else if (event.target.classList.contains("b")) {
output.textContent = output.textContent === "" ? "TOPIC B" : "";
} else {
output.textContent = output.textContent === "" ? "TOPIC C" : "";
}
}
}.hidden { display:none; }
.active { color:red; }<div class = "wrapper">
<!-- Don't set up events with inline HTML attributes. -->
<label><input type = "checkbox" class = "hidden topic a">Try it 1</label>
<label><input type = "checkbox" class = "hidden topic b">Try it 2</label>
<label><input type = "checkbox" class = "hidden topic c">Try it 3</label>
</div>
<!-- No matter which button gets clicked, the appropriate
content will go here. -->
<div class = "output"></div>Ваш ответ кажется информативным, но я не принял его, так как он не делает то, что я хочу. Попробуйте 1 включить и выключить тему A, попробуйте 2, сделайте то же самое с другой текстовой темой B и так далее.
@cgss Если вы хотите больше эффекта переключения, нам просто нужно использовать флажки вместо кнопок. Я изменю код, чтобы отразить это.
@cgss См. обновленный ответ. Кроме того, вы должны проголосовать за все полезные ответы.
Извините, но все еще не идеально. Что, если я хочу, чтобы два текста отображались одновременно? (хотя я проголосовал за)
@cgss Вы не спрашивали об этом варианте использования. Пожалуйста, поймите, что SO не является службой написания кода. Мы здесь не для того, чтобы писать для вас «идеальный» код. Мы здесь, чтобы объяснить, почему определенные подходы лучше или хуже, и показать примеры того, что мы имеем в виду. Вы по-прежнему несете ответственность за получение этой информации и продолжение ее изучения. Код, который я предоставил, показывает передовой подход к решению заданного вами вопроса. Настройка здесь должна быть чем-то, над чем вы должны теперь работать с форой, которую предоставили мои (или другие) ответы.
Чтобы попытаться связать воедино мои комментарии и комментарии Кита — перегруппируйте и делегирование событий — в зависимости от того, как устроена ваша страница, вы можете обойтись более упрощенной разметкой HTML и кодом JS.
Например, предположим, что у вас есть ряд разделов, и каждый раздел имеет абзац и соответствующую кнопку непосредственно под ним. Используя делегирование событий, вы можете добавить одного слушателя к содержащему элементу (в данном случае .container) и заставить его перехватывать все события от своих дочерних элементов, поскольку они «пузырятся» в DOM.
Обработчик слушателя сначала проверит, соответствует ли элемент, вызвавший событие , элементу кнопки, а затем захватит ️previousElementSibling этой кнопки (элемент абзаца). Используя CSS и метод classList toggle, вы можете включать/выключать этот текст, изменять его цвет и т. д. В этом примере он появляется/исчезает.
// Get the container element
const container = document.querySelector('.container');
// Assign one listener to the container
container.addEventListener('click', handleClick);
// Using the event from the listener
// 1) Check the target of the event is a button
// 2) Grab the button's sibling paragraph element
// 3) Toggle the show class on the paragraph
function handleClick(e) {
if (e.target.matches('button')) {
const para = e.target.previousElementSibling;
para.classList.toggle('show');
}
}.container { display: grid; grid-template-columns: repeat(2, 100px); gap: 0.25rem;}
.container section { background-color: #efefef; border: 1px solid #cdcdcd; padding: 0.25rem; text-align: center;}
p { opacity:0; transition: opacity 0.2s ease-in-out;}
.show { opacity: 1; }<section class = "container">
<section>
<p>Text one</p>
<button type = "button">Toggle text</button>
</section>
<section>
<p>Text two</p>
<button type = "button">Toggle text</button>
</section>
<section>
<p>Text three</p>
<button type = "button">Toggle text</button>
</section>
<section>
<p>Text four</p>
<button type = "button">Toggle text</button>
</section>
</section>
Отвечает ли это на ваш вопрос? onClick, чтобы получить ID нажатой кнопки