× К оглавлению На главную Об авторе

Дата и время публикации:

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


1. Что это такое

Динамическое добавление стилей каскадных таблиц CSS (далее по тексту – стили) в заголовок документа НTML позволяет подгружать нужные правила декорирования в начале использования формы управления.

Как показано в листинге 1.1, обычно стили, содержащиеся в отдельном файле с расширением .css, импортируются ("подключаются") в документ HTML один раз, когда он загружается, т.е. статически.

Листинг 1.1

  . . . 
  <head>
  . . . 
  <link rel="stylesheet" type="text/css" href="mystyles.css" media="screen" />
  . . . 
 </head>
  . . . 

Поэтому, когда браузер в ходе лексического разбора документа сталкивается на элемент с именем (тэгом) <link>, он производит загрузку файла с сервера по ссылке, заданной атрибутом href, а затем все остальное.

Примечание В листинге 1.1 считается, что «сыграет» автоподстановка доменного имени сервера, взятой из объекта window.location или location, которая содержит информацию об текущем местонахождении документа HTML на сервере. В обратном случае, если такой возможности нет, нужно писать функцию JS, возвращающую абсолютный URL, как показано в листинге 1.1.1. Листинг 1.1.1
 1 function absUrlGetFromLocalHref(href)
 2 {
 3  var slash = (href[0] == '/' ?'':'/'); 
 4  return ( location ? location.host+splash+href : 
 5		 (window.location ? window.location.host+splash+href :'')); 
 6 } 
В строке 3 вычисляем нужно ли подставлять "косой" слэш или нет. В строках 4-5 составляем абсолютный URL из имени хоста сервера, свойства location.host, из "косого" слэша и локального HREF, где находиться файл на сервере. При этом учитывается, что одним брузерам будет достаточно указать просто объект location, как показано в строке 4, а другие потребуют window.location, как в строке 5.

При этом, атрибут real="stylesheet", указывает на отношение подгружаемого контента в виде файла со стилями в текущем документе HTML, а необязательный атрибут type содержит "text/css".

2. Использование

Для организации горячего подключения файла со стилями,вернее динамического импорта, разделим действо на несколько частей:

– создание узла <link> с атрибутами (Листинг 2.2);

– определение объекта styleSheet и свойства СSSRule (Листинг 2.3);

– запуск проверки завершения импорта стилей (Листинг 2.4);

– вставка узла <link> в заголовок документа HTML (Листинг 2.5).

В строке 1-9 листинга 2.2 производим создание узла <link> в соответствии с форматом, приведенным в начале.

Листинг 2.2

 1 function loadStyleSheet( myHref, fn, scope ) {
 2  var head = document.getElementsByTagName( 'head' )[0],  // ссылка на узел <head> и
 3      link = document.createElement( 'link' );            // создание  узла <head> с атрибутами
 4  link.setAttribute( 'href',getAbsUrlsForMyHref(myHref)); // где искать файл каскадных 
 5  link.setAttribute( 'rel', 'stylesheet' );               // таблиц в формате заданным
 6  link.setAttribute( 'type', 'text/css' );                // для их использования 
 7    

В строках 8-15 листинга 2.3 определяем объект импорта стилей CSS из-за старых версий MSIE, которые до 9-ой версии MSIE использовали объект styleSheet и свойство rules, в то время как остальные браузеры используют для этого объект sheet и свойство cssRules.

Листинг 2.3

 8  var sheet, cssRules; 
 9  if ( 'sheet' in link ) {                  // узнаем, есть ли объекты с именованным индексом 'sheet'.
10    sheet = 'sheet'; cssRules = 'cssRules'; // устанавливаем 
11  }
12  else {
13      sheet = 'styleSheet'; cssRules = 'rules';
14  }	
Примечание В JS до свойств и объектов внутри родителя можно достучаться с использованием именованной индексации, что является для него нормальным поведением, в то время как в ассоциированных массивах используется числовая индексация. Поэтому, в случае использования с ними именованной индексации, ассоциированный массив перестраивается в объект с возможной потерей некоторых свойств и методов из-за их некорректной работы. Процедуру выбора между объектом sheet и styleSheet можно сократить до двух строк, как показано в листинге 2.3.1. Листинг 2.3.1
 8    var sheet= link.sheet ? link.sheet : link.styleSheet;
 9  var cssRules = sheet.cssRules ? sheet.cssRules : sheet.rules;
10 
11
12
13
14

Как показано в листинге 2.4 проверка завершения импорта стилей в документ HTML запускается раньше чем она фактически состоится позднее в листинге 2.4. При этом, сама проверка заключается в том, что на протяжение 15 секунд с интервалом 10 миллисекунд ждем завершения импорта стилей CSS.

Листинг 2.4

17   var interval_id = setInterval( function() { 
18            try {
19         if (link[sheet] && link[sheet][cssRules].length ) {
20           if (window.clearInerval)                // дождались,
21              window.clearInerval(interval_id);    // останавливаем
22           else		                     // интервальный таймер
23             clearInerval(interval_id);
24           if(window.clearTimeout)                 // таймер однократного
25               clearTimeout(interval_id);          // действия
26             else
27                clearTimeout(interval_id);
28	     fn.call( scope || window, true, link ); // производим вызов функции
29         }					     // обратного вызова
30      }catch(e) { console.log(e.message); } finally{}
31  }, 10),
32       timeout_id = setTimeout( function() {       // не дождались
33           if (window.clearInerval)                // останавливаем
34              window.clearInerval(interval_id);    // интервальный таймер
35           else
36             clearInerval(interval_id);
37          head.removeChild( link );                // удаляем узел <link>
38          fn.call( scope || window, false, link ); 
39       }, 15000 ); 

В строке 19 листинга 2.4 проверяется не только факт получения файла со стилями CSS, но и сам факт наличия в нем правил. Поэтому в случае, если по истечению 15 секунд импорт не состоялся, в строке 37 производится удаление узла <link>.

Примечание В строках 18-30 листинга 2.4 встроен блок catch для перехвата ошибок, которые могут возникнуть при работе с объектами и/или при запуске функции обратного вызова fn в строке 28. Операторы try, catch и finaly обрабатывают почти все ошибки, которые могут случится при выполнение кода на отрезке между оператором try и catch, которые соответственно определены в строках 18 и 30 листинга 2.4. При этом, использование оператора finaly так же в строке 30 позволит продолжить выполнение кода несмотря на выявленные в коде ошибки.

В строке 37 листинга 2.5 вставляем узел , тем самым инициируем загрузку файла стилей по указанной ссылке href, а в строке 38 возвращаем ссылку на созданный узел.

Листинг 2.5

40    head.appendChild( link );  
41    return link; 
42  }  
43

3. Пример использования

3.1 Приведен в листинге 3.1

Листинг 3.1

1   loadStyleSheet( '/path/to/my/stylesheet.css', function( success, link ) {
2       if ( success ) {
3      // код будет выполнен, если стили CSS были импортированы
4      }
5      else {
6      // код для выполнения, если они не были импортированы
7      }
8  } );
Примечание Одной из характерных сторон JS – это функции обратного вызова, и если выразится словами известного классика «в них сила и его проклятье». Почему? Потому что в JS все рассчитано на отложенные вызовы, реализующие асинхронный режим обмена данными с сервером без блокировки браузера клиента, потому что все в WEB заточено именно на получение/передачу информации, а сам функционал вторичен – первичны данные. Соответственно, это легко реализуется с помощь временных интервалов периодически формируемых после запуска setInterval() и однократного действия, вызываемых через setTimeout(), как показано в листинге 2.4. Таким образом, любителям синхронного режима, коих у нас достаточно, JS покажется скудным и однообразным, не позволяющий загружать процессор «пустыми» вычислениями и пугать пользователя «подвисаниями» браузера.

4.Библиография

1) 4 methods of adding CSS to HTML

2) Using window.location to Redirect to a Different URL with JavaScript

3) MDN.<link>

4) stylesheet.onload: or lack thereof

5) CSS file added dynamically is not loaded

6) Obj.location

7) window.location

8) cssRules collection

9) styleSheet object

10) JavaScript Arrays

11) MDN.JavaScript timers

12) JavaScript try/catch/finally Statement