使用 Javascript 将样式动态添加到样式表,但我收到“无法读取未定义的属性'长度'”错误

Using Javascript to dynamically add styles to stylesheet but I get a "Cannot read property 'length' of undefined" error

本文关键字:样式 未定义 读取 属性 错误 长度 添加 动态 Javascript 使用      更新时间:2023-09-26

我目前正在尝试制作自己的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 或仅涵盖可能同时使用这两种模型的较新版本:样式工作表对象、规则对象

这里有一些 Opera 文档:动态样式 - 使用 JavaScript 操作 CSS

这里还有一些信息:样式表对象,CSS 规则对象。

与所有网络资源一样,请以严重的怀疑态度对待它,寻找其他来源并在尽可能多的浏览器(尤其是旧浏览器)中进行测试,测试,测试。

运行代码:

> 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 对象实现类型属性(即使 MSDN 文档说它实现了,但这是针对 IE 9 及更高版本实现的 W3C 模型)。

然后:

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

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

      // 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[0]屏幕media[1]打印,因此您需要循环访问媒体规则。

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