2013-10-15 7 views
0

В настоящее время я пытаюсь создать свой собственный полиполк, который позволит старым браузерам, таким как Internet Explorer, читать и выполнять медиа-запросов с использованием традиционных селекторов css. Поток процесса идет что-то вроде этого:Использование Javascript для динамического добавления стилей в таблицу стилей, но я получаю сообщение «Can not read property» undefined »

  1. перебирать каждую таблицу стилей найти в документе
  2. Выполнить по каждому правилу стиля в таблице стилей поисков медиазапросов
  3. Определить, что размер устройства мы планируем затем применить соответствующий «идентификатор "
  4. Динамически добавить CSS строку с селектором в существующую таблицу стилей

идея заключается в том, что polyfill будет искать для запросов СМИ затем применить родительский„ID“в го е тело, соответствующее размеру устройства, например:

#tablet .wrap { ... } 
#mobile .wrap { ... } 
#desktop .wrap { ... } 

Вот что Javascript выглядит так далеко:

var styleSheets = document.styleSheets; 
var debug = false; 
var ruleParts = mediaPart = rules = compiledSel = className = ''; 
var dimS = dimB = 0; 
var idList = Array('smallMobile','mobile','tablet','smallDesktop','desktop'); 

// run through each stylesheet 
for(i = 0; i < styleSheets.length; i++) { 

    // If uncommented will show each stylesheets rules contained therein 
    if(debug) { 
     console.log(styleSheets[i].cssRules); 
    } 

    // run through each rule declaration 
    for(a = 0; a < styleSheets[i].rules.length; a++) { 

     if(styleSheets[i].rules[a].type == 4) { 

      mediaPart = styleSheets[i].rules[a].media[0].split(' and '); 

      dimS = parseInt(mediaPart[0].replace(/[():A-Za-z$-]/g, "")); 
      dimB = parseInt(mediaPart[1].replace(/[():A-Za-z$-]/g, "")); 

      if(dimS > 0 && dimB < 418) { 
       className = idList[0]; 
      } else if(dimS > 419 && dimB < 767) { 
       className = idList[1]; 
      } else if(dimS > 768 && dimB < 1024) { 
       className = idList[2]; 
      } else if(dimS > 1025 && dimB < 1201) { 
       className = idList[3]; 
      } else { 
       className = idList[4]; 
      } 


      if(styleSheets[i].rules[a].cssRules.length > 1) { 

       for(b = 0; b < styleSheets[i].rules[a].cssRules.length; b++) { 

        ruleParts = styleSheets[i].rules[a].cssRules[b].cssText.split('{'); 
        rules = ruleParts[1].split('}'); 

        addCSSRule(styleSheets[i], '#'+ className +' '+ ruleParts[0], rules[0], 1); 

        /* 
        *  Investigate why the .insertRule() and addRule() are failing specifically what is causing them to break 
        *  
        */ 

       } 

      } else { 

      } 

     } 

    } 
} 

function addCSSRule(sheet, selector, rules, index) { 
    if(sheet.insertRule) { 
     sheet.insertRule(selector + "{" + rules + "}", index); 
    } else { 
     sheet.addRule(selector, rules, index); 
    } 
} 

Сейчас все работает так, как я хочу, даже добавление правила CSS в таблицу стилей, однако я получаю эту ошибку, и я не совсем уверен, в какой момент:

Uncaught TypeError: Cannot read property 'length' of undefined 

Если удалить вызов функции этой линии, я не получаю ошибку:

addCSSRule(styleSheets[i], '#'+ className +' '+ ruleParts[0], rules[0], 1); 

Так что я не уверен, что происходит во время вызова функции и чтения .length

Мой HTML выглядит следующим образом:

<!DOCTYPE html> 
<head> 
<title>Style Manipulation VIA Javascript</title> 

<link rel="stylesheet" href="css/test.css" /> 
<link rel="stylesheet" href="css/typo.css" /> 

</head> 
<body> 

<div class="wrap"> 
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p> 
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p> 
</div> 

В целом, мне нужно, чтобы выяснить, почему длина свойства не может быть прочитана и что в вызове функции addCSSRule вызывает ошибку.

+0

Что такое 'styleSheets [i] .rules [a] .cssRules'? Выполнение 'document.styleSheets [0] .rules [0] .cssRules' даст мне _undefined_, но вы пытаетесь получить доступ к свойству _length_ этого. –

+0

@PaulS. Это повторяется через все правила стиля в данной таблице стилей. В целом это говорит мне, сколько правил находится в таблице стилей. Путь таблиц стилей довольно сложный, если вы делаете что-то вроде: 'console.log (styleSheets [i] .cssRules);' Это даст вам все правила, но внутри медиа-запросов, которые определены в правиле, которое вы также найдет другой список правил со всеми правилами, которые входят в медиа-запрос. Итак, перейдем к правилам, шифруя все, что не относится к типу == 4, исключающему все другие традиционные не-медиа-запросы. –

+0

Я согласен с тем, что может существовать дополнительный список правил, но вы предполагаете существование и на самом деле не проверяете для него и что он обходит _length_, заставляет его смотреть на меня очень подозрительно. Войдите в систему только перед тем, чтобы вы могли увидеть, была ли там ошибка. –

ответ

1

Существуют значительные различия между IE и W3C реализаций StyleSheets объект, надеюсь, следующий достаточно толковый, чтобы помочь:

function getStyleRules() { 
    var rule, rules; 
    var sheet, sheets = document.styleSheets; 
    var ruleCssText = ['Rules:','',] 

    for (var i=0, iLen=sheets.length; i<iLen; i++) { 
     sheet = sheets[i]; 

     // Get the rules using: 
     // 
     //  W3C model  IE model 
     rules = sheet.cssRules || sheet.rules; 

     for (var j=0, jLen=rules.length; j<jLen; j++) { 
     rule = rules[j]; 

     // The selector is available here in both models, 
     // but uppercase in IE so set to lower case 
     alert('Selector: ' + rule.selectorText.toLowerCase()); 

     // Getting the actual rule text 
     // W3C model - selector and rule 
     if (rule.cssText) { 
      ruleCssText.push(rule.cssText); 

     // IE model - rule only, doesn't include selector 
     } else if (rule.style) { 
      ruleCssText.push(rule.style.cssText.toLowerCase()); 
     } 
     } 
     alert(ruleCssText.join('\n')); 
    } 
} 

Существует документация на MSDN модели IE, но я не уверен, что если он все еще покрывает старую IE или только новые версии, которые также могут использовать обе модели: styleSheet object, rule object

Существует некоторая документация Opera здесь: Dynamic style - manipulating CSS with JavaScript

а также некоторая информация здесь: The styleSheet object, The CSS Rule object.

Как и все веб-ресурсы, возьмите его с серьезным скептицизмом, найдите другие источники и протестируйте, протестируйте, испытайте как можно больше браузеров (особенно старых).

Запуск код:

> TypeError: styleSheets[i].rules is undefined 
> 
> for(a = 0; a < styleSheets[i].rules.length; a++) { 

Здесь вы смесительный ИЭ (правила) и W3C (cssRules) модели. Лучше просто получить правила объекта сразу: -

var sheetRules = styleSheets[i].rules || styleSheets[i].cssRules; 
    for(a = 0; a < sheetRules.length; a++) { 

Тогда у вас есть:

if (sheetRules[a].type == 4) { 

но модель IE не реализует типа свойства для правил объекта (даже если в документации MSDN говорится, что это так, это для модели W3C, реализованной IE 9 и более поздними версиями).

Тогда:

>  mediaPart = sheetRules[a].media[0].split(' and '); 

Обратите внимание, что СМИ является свойством листа, а не правило, так:

 // Perhaps mediaParts (plural)? 
     mediaPart = styleSheets[i].media; 

И просто быть противным, модель IE имеет media с типом строки, но он пуст. Вы можете получить его текст, используя:

styleSheets[0].cssText.replace(/\s+/g,' ').match(/@media.+}[^{]+}/) 

.

>  // TypeError: mediaPart[1] is undefined 
>  dimB = parseInt(mediaPart[1].replace(/[():A-Za-z$-]/g, "")); 

Здесь вы, кажется, ожидаете «и», чтобы быть в правиле. Вы не дали пример ваших правил, но если они похожи:

@media screen, print { ... } 

затем СМИ список правил СМИ: media[0]является экраном и media[1] является печати, так что вы хотите перебирать правила СМИ.

Во всяком случае, этого достаточно.

+0

Привет, спасибо за ответ, к сожалению, прямо сейчас у меня нет времени, чтобы реализовать это, но я возьму качели с этим подходом коротко и, надеюсь, это сработает !!! Еще раз спасибо! –

+0

Я думаю, что это намного грязнее, чем вы думаете ... :-( – RobG

 Смежные вопросы

  • Нет связанных вопросов^_^