Javascript.RU

Документ: навешиваем ярлычки.

Пост следующий, как продолжение темы о документе. Про классы элементов и их применение.

Пространные рассуждения

Что такое класс элемента? Кто-то ответит, что это эдакий штуковин, чтобы верстальщики могли стили прикрутить.

На самом деле, все значительно глубже. Класс — это именно класс элемента, то, что отделает его от других и наделяет особыми свойствами, и это касается не только css.
В jQuery-style программировании я часто сталкивался с тем, что нужным элементам присваиваются инлайновые стили, мол, ты, элемент, будешь красный и полужирный Ариала двадцатого с подчеркиванием, а ты, дружок, будешь display: none. А потом состояние проверяется через computedStyle, вызывая лавины reflow в совершенно ненужных местах. А через полгода грядет редизайн сайта, и он начинает пестрить красным ариалом, хотя сам уже давно сделан на черном Мириад Про.

Так вот, меняя элемент, мы должны менять не его отображение, а его роль в документе. То есть, класс или id. И это и есть пресловутая семантика.

Практика

А теперь вспомним предыдущий пост и посмотрим, какие же плюсы нам может это дать.

С семантичным кодом удобно и приятно работать. Давайте рассмотрим в комментариях следующий код, который добавляет этой странице подсветку ответной скобки при наведении на скобку в скриптах.

Опять-таки, отслеживаем любое событие и смотрим, чьё оно.

if (!highlightCode) var highlightCode = { /* мухи отдельно, котлеты отдельно. Храним связанные функции в одном объекте */
	dispatcher: { /* диспетчер. Собираем до кучи обработчики */
		mouseover: function(e){
			var trigger = e.srcElement||e.target; /* кто такой? */
			if (trigger.className && /(^|\s)+br0(\s|$)+/.test(trigger.className)){ /* у него есть класс br0? */
				highlightCode.highlight(trigger); /* запускаем подсветку */
			};
		},
		mouseout: function(e){
			var trigger = e.srcElement||e.target; /* кто такой? */
			if (trigger.className && /(^|\s)+highlight-[^\s]+(\s|$)+/.test(trigger.className)){ /* уже подсвечен? */
				highlightCode.unhighlight(trigger); /* снимаем подсветку */
			};
		}
	},
	highlight: function(o){ /* подсветка */
		var targetBrace = o.innerHTML; /* а что за скобочка? */
		switch (targetBrace){
			case "(": var matchingBrace = ")"; var browseForward = true;  break; /* если это "(", то ищем ")" дальше по документу */
			case ")": var matchingBrace = "(";	var browseForward = false; break; /* если это ")", то ищем "(" раньше */
			case "{": var matchingBrace = "}"; var browseForward = true;  break;
			case "}": var matchingBrace = "{"; var browseForward = false; break;
			case "[": var matchingBrace = "]"; var browseForward = true;  break;
			case "]": var matchingBrace = "["; var browseForward = false; break;
			default: return; /* это не нужная нам скобочка. Выходим и ничего не делаем */
		};
		var disbalance = 1; /* баланс скобок. Нарушен */
		
		var testElement = o; /* начинаем поиски от текущего элемента */
		while (testElement){ /* условие не должно быть пустым. Правило хорошего тона, не более */
			testElement = browseForward?testElement.nextSibling:testElement.previousSibling; /* выбираем следующий элемент, назад или вперед */
			if (!testElement) break; /* это не элемент. Кончились? Завершаем цикл. */
			if (!testElement.className || !/(^|\s)+br0(\s|$)+/.test(testElement.className)) continue; /* это не скобочка. Ищем другой элемент */
			switch (testElement.innerHTML){ /* баланс скобок */
				case targetBrace:   disbalance++; break;
				case matchingBrace: disbalance--; break;
				default: continue; /* это не наша скобка, пропускаем */
			};
			if (disbalance == 0){ /* баланс сошелся? */
				o.relatedBrace = testElement; testElement.relatedBrace = o; /* делаем скобки побратимами */
				o.className += " highlight-matching"; /* одной ставим класс */
				testElement.className += " highlight-matching"; /* и другой */
				break; /* выходим из цикла */
			};
		};
		if (!testElement){ /* если после выхода из цикла проверяемый элемент Null, то баланс так и не сошелся */
			o.className += " highlight-nonmatching"; /* подсвечиваем одинокую скобку, по-другому */
		}
	},
	unhighlight: function(o){ /* снимаем подсветку */
		o.className = o.className.replace(/(^|\s)+highlight-[^\s]+(\s|$)+/, " "); /* убираем класс */
		if (o.relatedBrace){ /* и у побратима, если есть, тоже */
			o.relatedBrace.className = o.relatedBrace.className.replace(/(^|\s)+highlight-[^\s]+(\s|$)+/, " ");
		};
	},
	init: function(){
		if (arguments.callee.runOnce) return false; /* защита от повторного запуска */
		else arguments.callee.runOnce = true;
		
		for (var i in this.dispatcher){ /* проходим по всему диспетчеру и привязываем его обработчики */
			if (typeof this.dispatcher[i] == "undefined") continue;
			if (document.addEventListener) document.addEventListener(i, this.dispatcher[i], false)
			else if (document.attachEvent) document.attachEvent('on' + i, this.dispatcher[i]);
		};
		var myCSS = document.createElement("style"); /* создаем стиль и заполняем его */
		myCSS.type = "text/css";
		myCSS.innerHTML = "\
.source .highlight-matching {color: red; font-weight: bold}\
.source .highlight-nonmatching {color: darkblue; font-weight: bold}\
";
		document.getElementsByTagName("head")[0].appendChild(myCSS) /* ...и прикрепляем */
	}
};
highlightCode.init(); /* поехали! */

В этом примере css вставляется через яваскрипт (увы, я не имею доступа к хостингу javascript.ru ), но в Вашем проекте, конечно, стили должны подключаться из файла.

CSS позволяет нам посредством себя же управлять отображением документа. Это не секрет. И это можно использовать в своих коварных целях.

На практике есть два приема для этого: классы-модификаторы и классы-переключатели.

Класс-модификатор — класс, который, будучу добавленным к элементу, незначительно меняет его отображение. Одноименные классы, добавленные к разнотипным элементам, могут менять разные свойства, но логически должны составлять единое целое. Например, логическое выделение. Класс-модификатор — это, например, highlight-matching в предыдущем примере.

Класс-переключатель меняет отображение своих детей. Например, на лету и в одном месте поменять цвет сайта или размер шрифта, почему нет?

Чтобы проиллюстрировать класс-переключатель, немного пошалим и с грязными ногами, но с чистыми намерениями внедримся в шаблон этой самой страницы:

if (!inactiveHandler) var inactiveHandler = {
	hareAnimation: function(vector){
		var thisFunction = arguments.callee;
		
		if (typeof(vector) == "undefined"){
			vector = thisFunction.vector;
		} else {
			thisFunction.vector = vector;
		};
		
		if (!thisFunction.frame) thisFunction.frame = 0;
		thisFunction.frame = thisFunction.frame + vector;
		if (vector > 0){
			if (thisFunction.frame > 4){
				thisFunction.frame = 4;
				return;
			};
		} else {
			if (thisFunction.frame < 0){
				thisFunction.frame = 0;
				return;
			};
		}
		document.body.className = document.body.className.replace(/(^|\s)+hare-sprite-frame-\d(\s|$)+/, " ") + "hare-sprite-frame-" + thisFunction.frame;
		
		setTimeout(function(){thisFunction()}, 40);
	},
	dispatcher: {
		mouseover: function(e){
			if(!(e.relatedTarget||e.fromElement)) inactiveHandler.hareAnimation(-1);
		},
		mouseout: function(e){
			if(!(e.relatedTarget||e.toElement)) inactiveHandler.hareAnimation(1);
			
		}
	},
	init: function(){
		if (arguments.callee.runOnce) return false;
		else arguments.callee.runOnce = true;

		for (var i in this.dispatcher){
			if (typeof this.dispatcher[i] == "undefined") continue;
			if (document.addEventListener) document.addEventListener(i, this.dispatcher[i], false)
			else if (document.attachEvent) document.attachEvent('on' + i, this.dispatcher[i]);
		};
		var myCSS = document.createElement("style");
		myCSS.type = "text/css";
		myCSS.innerHTML = "\
.hare-logo {width: 336px;height: 76px;background: url(/files/u4363/jssprite1.gif) 0px 0px no-repeat}\
.header-table-login {background: url(/files/u4363/jssprite2.gif) 0px -0px repeat-x}\
.hare-sprite-frame-1 .hare-logo, .hare-sprite-frame-1 .header-table-login {background-position: 0px -76px}\
.hare-sprite-frame-2 .hare-logo, .hare-sprite-frame-2 .header-table-login {background-position: 0px -152px}\
.hare-sprite-frame-3 .hare-logo, .hare-sprite-frame-3 .header-table-login {background-position: 0px -228px}\
.hare-sprite-frame-4 .hare-logo, .hare-sprite-frame-4 .header-table-login {background-position: 0px -304px}";
		document.getElementsByTagName("head")[0].appendChild(myCSS)
		var images = document.getElementsByTagName("img");
		for (var i=0; i<images.length; i++){
			if (/\/misc\/logo.gif/.test(images[i].src)){
				var image = images[i];
				var parent = image.parentNode;
				var mylogo = document.createElement("div");
				mylogo.className = "hare-logo";
				parent.insertBefore(mylogo, image);
				parent.removeChild(image);
			};
		};
	}
};
inactiveHandler.init();

Запустили? Ничего не произошло? Пролистайте в самый верх страницы и уведите курсор куда-нибудь со страницы, например, в заголовок окна браузера. Теперь видите?

Заключение

Это я всё к чему. Рассматривая страницу как документ, а не как разрозненный набор элементов, мы можем работать с ней как со стройной системой, легко и просто. Буквально, подежать в руках и покрутить как кубик Рубика.

+2

Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
1 + 6 =
Введите результат. Например, для 1+3, введите 4.
 
Поиск по сайту
Другие записи этого автора
subzey
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Популярные таги
Последние комментарии
Последние темы на форуме
Forum