javascript - 使用 Javascript 动态添加样式到样式表,但我得到一个 "Cannot read property ' 长度'的未定义“错误

标签 javascript css media-queries polyfills

我目前正在尝试制作自己的 polyfill,它将允许 Internet Explorer 等较旧的浏览器能够使用传统的 css 选择器读取和执行媒体查询。流程是这样的:

  1. 遍历在文档中找到的每个样式表
  2. 遍历样式表中的每个样式规则以搜索媒体查询
  3. 定义我们的目标设备尺寸,然后应用适当的“id”
  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 函数调用中的什么导致了错误。

最佳答案

styleSheets 对象的 IE 和 W3C 实现之间存在显着差异,希望以下解释足以帮助您:

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'));
    }
}

IE 模型的 MSDN 上有文档,但我不确定它是否仍然涵盖旧版 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++ ) {

在这里您混合了 IE(规则)和 W3C(cssRules)模型。最好只获取规则对象一次:-

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

那么你有:

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

但是 IE 模型没有为 rules 对象实现 type 属性(即使 MSDN 文档说它实现了,那是针对 IE 实现的 W3C 模型9 及更高版本)。

然后:

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

请注意,media 是工作表的属性,而不是规则的属性,因此:

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

说句脏话,IE 模型有一个字符串类型的媒体属性,但它是空的。您可以使用以下方式获取它的文本:

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 是媒体规则的列表:media[0]screenmedia[1]print,因此您想要迭代媒体规则。

无论如何,现在就足够了。

关于javascript - 使用 Javascript 动态添加样式到样式表,但我得到一个 "Cannot read property ' 长度'的未定义“错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19393004/

相关文章:

javascript - 匿名函数变量作用域[js、ajax]

javascript - Node 中数组解构的奇怪行为

jquery - 整个页面加载后播放CSS3动画

html - 媒体查询在 html 电子邮件中不起作用吗?

媒体查询的 CSS 网格布局更新

给定两个函数的Javascript找到交集

html - 当行内显示不起作用时,行内显示 <div>

html - 浏览器兼容性问题 : Throwing off layout in Firefox & IE

CSS 媒体查询不显示在移动设备上

javascript - 允许 SVG 文本在 Angular 中可编辑吗?