Книга: JavaScript. Подробное руководство, 6-е издание

16.5. CSS-классы

16.5. CSS-классы

Альтернативой использованию отдельных CSS-стилей через свойство style является управление значением HTML-атрибута class. Изменение класса элемента изменяет набор селекторов стилей, применяемых к элементу, что может приводить к изменениям значений сразу нескольких CSS-свойств. Предположим, например, что вам требуется привлечь внимание пользователя к отдельным абзацам (или другим элементам) в документе. В этом случае можно было бы сначала определить особый стиль оформления для любых элементов с классом «attention»:

.attention { /* Стили для элементов, требующих внимания пользователя */
  background-color: yellow; /* Желтый фон */
  font-weight: bold; /* Полужирный шрифт */
  border: solid black 2рх; /* Черная рамка */
}

Идентификатор class в языке JavaScript является зарезервированным словом, поэтому HTML-атрибут class в JavaScript-сценариях доступен в виде свойства с именем className. Ниже приводится пример, который устанавливает и очищает свойство className элемента, добавляя и убирая класс «attention»:

function grabAttention(e) { е.className = "attention"; }
function releaseAttention(e) { e.className = ""; }

HTML-элементы могут быть членами более чем одного CSS-класса - атрибут class может содержать целый список имен классов, разделенных пробелами. Имя className не совсем точно отражает смысл свойства: правильнее было бы дать ему имя classNames. Функции выше предполагают, что свойство className будет определять ноль или одно имя класса, и они непригодны в случаях, когда может использоваться более одного имени класса. Если элемент уже принадлежит некоторому классу, вызов функции grabAttention() для этого элемента затрет имя класса, присутствующее в свойстве className.

Стандарт HTML5 решает эту проблему, определяя свойство classList во всех элементах. Значением этого свойства является объект DOMTokenList: подобный массиву объект (раздел 7.11), доступный только для чтения, элементы которого содержат отдельные имена классов, присвоенных элементу. Однако самыми важными в нем являются не элементы массива, а методы add() и remove(), добавляющие и удаляющие отдельные имена классов из атрибута class элемента. Метод toggle() добавляет имя класса, если оно отсутствует, и удаляет в противном случае. Наконец, метод contains() проверяет присутствие указанного имени класса в атрибуте class.

Подобно другим классам коллекций в модели DOM, объект DOMTokenList является «живым» представлением множества классов в элементе, а не статическим слепком, который был действителен только в момент обращения к свойству classList. Если сценарий получит объект DOMTokenList, обратившись к свойству classList элемента, и затем изменит свойство className этого элемента, то выполненные изменения немедленно отразятся на полученном объекте DOMTokenList. Аналогично любые изменения, выполненные в объекте DOMTokenList, немедленно отразятся на значении свойства className.

На момент написания этих строк свойство classList не поддерживалось ни одним из текущих броузеров. Однако эту удобную функциональность легко можно реализовать самому, как показано в примере 16.5. Подобная реализация, позволяющая интерпретировать атрибут class элемента как множество имен классов, существенно упрощает выполнение многих задач, связанных с обработкой CSS.

Пример 16.5. classList(): интерпретирует className, как множество CSS-классов

//
* Возвращает свойство classList элемента е. если оно содержит один класс.
* Иначе возвращает объект, имитирующий интерфейс DOMTokenList.
* Возвращаемый объект имеет методы contains(), add(), remove(), toggle() и toString(),
* позволяющие проверять и изменять набор классов элемента е. Если свойство classList
* имеет встроенную поддержку в броузере, функция возвращает объект, подобный массиву,
* который имеет свойство length и поддерживает возможность индексирования массива.
* Имитация объекта DOMTokenList не подобна массиву, но имеет метод toArray().
* который возвращает истинный массив имен классов элемента.
*/
function classList(e) {
  if (е.classList) return e.classList; // Вернуть e.classList, если имеется
  else return new CSSClassList(e); // Иначе попытаться подделать его
}
// CSSClassList - класс JavaScript, имитирующий объект DOMTokenList
function CSSClassList(e) { this.e = e; }
// Возвращает true, если e.className содержит класс с, иначе - false
CSSClassList.prototype.contains = function(c) {
  // Проверить, является ли с допустимым именем класса
  if (с.length === 0 || c.indexOf(" ") != -1)
    throw new Error("Недопустимое имя класса: + с + .....);
  // Сначала проверить общие случаи
  var classes = this.e.className;
  if (!classes) return false; // e вообще не имеет классов
  if (classes === c) return true; // e имеет единственный класс,
                                  // имя которого точно совпадает с искомым
  // Иначе использовать RegExp для поиска с как отдельного слова
  // b - в регулярных выражениях соответствует границе слова,
  return classes.search(”b" + с + "b") != -1;
};
// Добавляет имя класса с в е.className, если оно отсутствует в списке
CSSClassList.prototype.add = function(c) {
  if (this.contains(c)) return; // Ничего не делать, если имя уже в списке
  var classes = this.e.className;
  if (classes && classes[classes.length-1] != " ")
    c = " " + с; // Добавить пробел, если необходим
  this.е.className += с; // Добавить имя с в className
};
// Удаляет все вхождения с из е.className
CSSClassList.prototype.remove = function(c) {
  // Убедиться, что с - допустимое имя класса
  if (с.length === 0 || c.indexOf(" ") != -1)
    throw new Error("Недопустимое имя класса: + с + .....);
  // Удалить все вхождения имени с как слова и все завершающие пробелы
  var pattern = new RegExp("b" + с + 'bs*' "g");
  this.e.className = this.e.className.replace(pattern, "");
};
// Добавляет имя с в e.className, если оно отсутствует в списке, и возвращает true.
// Иначе удаляет все вхождения имени с из e.className и возвращает false.
CSSClassList.prototype.toggle = function(c) {
  if (this.contains(c)) { // Если e.className содержит c
    this.remove(c); // удалить его.
    return false;
  }
  else { // Иначе:
    this.add(c); // добавить его.
    return true;
  }
};
// Возвращает само значение e.className
CSSClassList.prototype.toString = function() { return this.e.className; };
// Возвращает имена из e.className
CSSClassList.prototype.toArray = function() {
  return this.e.className.match(/bw+b/g) || [];
};

Оглавление книги


Генерация: 1.126. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз