Для таких простых визуальных действий, как скрыть-показать (или сделать зелёным), не нужны какие-то сложные идентификаторы элементов, не нужны циклы. Вообще не нужны сложные действия на javascript. Вся сложность здесь – в правильной структуре CSS – HTML.

Как скрыть-отобразить элемент по щелчку на другом элементе?

Существенным для правильной организации системы «скрыть-показать» элементы является расстояние между управляющим элементом (назовём его Кнопкой) и отображаемым элементом (назовём его Целью). Расстояние это может быть представлено в трёх вариантах:

  1. элементы находятся в подчинении (Цель вложена в Кнопку)
  2. элементы находятся в подчинении общего родителя
  3. элементы НЕ имеют общего родителя

Единственно правильная, простая и надёжная схема скрытия-отображения заключается в изменении класса родительского элемента Цели. Если рассмотреть структуру отображения в этом ключе, окажется что существенно разных варианта всего два: важно лишь, имеет ли Кнопка доступ к родительскому элементу Цели. В первом варианте сама Кнопка является этим родителем; во втором варианте у обоих элементов общий родитель; в обоих случаях доступ к родителю есть – по действию пользователя (щелчку мышью) мы просто меняем класс Кнопки либо класс parentNode Кнопки:

hidechild1.png

В третьем варианте Кнопка расположена чёрт знает как далеко от Цели, и у нас проблемы:

hidechild2.png

Как на javascript узнать, какая из Целей связана с данной Кнопкой? Самый простой вариант, который приходит в голову, – при генерации HTML страницы создавать идентификаторы, которые присваивать в виде id Целям и в виде какого-нибудь «левого», ненужного атрибута – Кнопкам. Так все обычно и делают. И так делают, даже когда идентификаторы вовсе не нужны.

Мы же поступаем полностью противоположным способом – всячески избегаем «навязчивых» атрибутов, даже когда они, казалось бы, нужны. В нашем случае решение приходит неизбежно, как паровоз по рельсам: если что-то нельзя соединить в DOM естественным образом при генерации на сервере, значит этого вовсе не нужно делать. Если нельзя создать на сервере Кнопки, соединённые с целями, значит Кнопки вовсе не нужно генерировать на Сервере – их нужно генерировать в самом javascript.

Все отображаемые и скрываемые Цели находятся в одном контейнере (назовём его Каталог). После загрузки страницы нам нужно подготовить элементы Каталога к определённым действиям пользователя (например, что-то делать с ними по щелчку мыши или при наведении мыши). Вот во время этой подготовки, когда мы получаем элементы Каталога в цикле, мы и будем генерировать элементы, управляющие отображением (наши Кнопки). И в этот момент нет ничего легче, чем присвоить текущей Кнопке javascript-свойство – ссылку на элемент-Цель:

Логика скрытия-отображения на CSS

Пусть, например, у нас управляющий элемент Кнопка (по которому кликаем) и скрытый элемент Цель находятся в одном общем контейнере (элементе Каталога). Тогда (по щелчку) надо менять класс контейнера, а в CSS описать, что должен делать этот изменённый класс. Пусть по умолчанию класс контейнера будет 'hidechild', и мы запишем в правилах CSS, что он должен запрещать отображение элементов с классом 'body':

При загрузке страницы все элементы с классом 'body' не будут видны на странице. По щелчку на управляющем элементе 'head' мы просто будем убирать (или добавлять) этот класс 'hidechild' родительскому контейнеру. Вот вкратце и вся логика. Она немного усложнится, если мы хотим создавать вложенные друг в друга контейнеры. Во всех случаях, для надёжности лучше не просто убирать «скрывающий потомков» класс, а ещё и добавлять «отображающий» класс – это упростит взаимоотношение нашей системы отображения с другими правилами CSS:

В случае, например, вложенности элементов-контейнеров друг в друга, логику отображения нижележащего элемента можно будет реализовать так:

– то есть Цель текущего контейнера может быть скрыта, а вложенного контейнера – показана; их отображение будет зависеть только от класса непосредственного родителя (но не от более далёких предков).

Защита от параноиков

Правильнее здесь было бы сказать, «удобства для параноиков», потому что я и сам параноик – хожу по незнакомым сайтам исключительно с включённым NoScript, то есть с отключенным по умолчанию javascript. В такой ситуации, зайдя на страницу нашего примера, я вообще не смогу увидеть содержимое контейнеров ('body'), а буду видеть лишь кнопки, по которым щёлкать с отключенным javascript бесполезно.

Это неправильно. Ведь скрываем мы часть содержимого для удобства пользователей – чтобы большое количество текста (и рисунков) не загромождало страницу, а пользователи могли бы видеть избранное, то, что нужно. Если же содержимым вообще невозможно управлять (скрывать-отображать по желанию пользователя), логичнее всё-таки отобразить всё, а не скрыть всё. Будет менее удобно, чем с управляющими кнопками, но не фатально (а «скрыть всё» – фатально).

Для обеспечения такой логики (без javascript показывать всё) нужно будет использовать ещё один, вышележащий контейнер. С учётом того, что наши каталоги – не единственное, что на нашем сайте требует javascript, разумно выбрать в этом случае в качестве управляющего контенера самый верхний элемент – body. Логика защиты проста:

  1. Назначаем на сервере элементу body класс nojs.
  2. При начале работы javascript (если он вообще начнёт работать), в одной из первых, инициализирующих функций, меняем класс body на js.
  3. В те правила CSS, которые в дальнейшем предполагается меняють с помощью javascript, добавляем вперёд лишний селектор – .js:

Таким образом, если javascript отключён, никто не поменяет класс body на js, и правила display:none; вообще не будут срабатывать (все элементы страницы будут сразу видны при загрузке).

Вот рабочий пример, иллюстрирующий скрытие-отображение элементов, генерацию кнопок (во втором случае) и удобства для параноиков: hidechild.html

Дилетант

Комментарии