将CSS文本转换为JavaScript对象

时间:2012-01-24 13:24:15

标签: javascript css

我将以下文字作为JavaScript字符串

.mybox {
 display: block; 
 width: 20px; 
 height: 20px;
 background-color: rgb(204, 204, 204);
 }

我想转换为JavaScript对象

var mybox = {
 'display': 'block',
 'width': '20px',
 'height': '20px';
 'background-color': 'rgb(204, 204, 204)';
};

任何想法或已制作的脚本?

4 个答案:

答案 0 :(得分:9)

2017年答案

function parseCSSText(cssText) {
    var cssTxt = cssText.replace(/\/\*(.|\s)*?\*\//g, " ").replace(/\s+/g, " ");
    var style = {}, [,ruleName,rule] = cssTxt.match(/ ?(.*?) ?{([^}]*)}/)||[,,cssTxt];
    var cssToJs = s => s.replace(/\W+\w/g, match => match.slice(-1).toUpperCase());
    var properties = rule.split(";").map(o => o.split(":").map(x => x && x.trim()));
    for (var [property, value] of properties) style[cssToJs(property)] = value;
    return {cssText, ruleName, style};
} /* updated 2017-09-28 */

描述

将以下cssText(字符串)传递给函数:

.mybox {
     display: block; 
     width: 20px; 
     height: 20px;
     background-color: rgb(204, 204, 204);
 }

...将提供以下对象:

{   cssText: ... /* the original string including new lines, tabs and spaces */, 
    ruleName: ".mybox",
    style: {
        "": undefined,
        display: "block",
        width: "20px",
        height: "20px",
        backgroundColor: "rgb(204, 204, 204)"
     }
}

用户还可以传递cssText,例如:

display: block; width: 20px; height: 20px; background-color: rgb(204, 204, 204);

特点:

  • 适用于CSSRule.cssText和。{ CSSStyleDeclaration.cssText
  • 转换CSS属性名称 (background-color)到JS属性名称(backgroundColor)。 它处理甚至非常不稳定的名字, 例如back%gr- -ound---color: red;(转换为backGrOundColor)。
  • 启用现有的大量修改 CSSStyleDeclarations(例如document.body.style)使用 一个电话 Object.assign(document.body.style, parseCSSText(cssText).style)
  • 当属性名称没有值(条目时)会失败 没有冒号)甚至反之亦然。
  • 更新2017-09-28:处理规则名称中的新行, 坍塌白色空间。
  • 更新2017-09-28:处理评论(/*...*/)。

怪癖:

  • 如果规则中的最后一个CSS声明以分号结尾, 返回的样式将包含一个名为""的空属性 一个undefined值,反映了后面的空字符串 分号。我认为这是一种正确的行为。
  • 如果属性值(字符串文字),函数将返回错误结果 例如,包括冒号或分号或CSS注释 div::before {content: 'test:test2;/*test3*/';}。我不知道 如何避免这种情况。
  • 目前,它会使用前缀转换属性名称 例如-somebrowser-someproperty错误地SomebrowserSomeproperty 而不是somebrowserSomeproperty。我想要一种不会破坏的补救措施 代码的简洁,因此我会花时间找一个。

实例



function parseCSSText(cssText) {
    var cssTxt = cssText.replace(/\/\*(.|\s)*?\*\//g, " ").replace(/\s+/g, " ");
    var style = {}, [,ruleName,rule] = cssTxt.match(/ ?(.*?) ?{([^}]*)}/)||[,,cssTxt];
    var cssToJs = s => s.replace(/\W+\w/g, match => match.slice(-1).toUpperCase());
    var properties = rule.split(";").map(o => o.split(":").map(x => x && x.trim()));
    for (var [property, value] of properties) style[cssToJs(property)] = value;
    return {cssText, ruleName, style};
} /* updated 2017-09-28 */

Example:
    var sty = document.getElementById("mystyle");
    var out = document.getElementById("outcome");
    var styRule = parseCSSText(sty.innerHTML);
    var outRule = parseCSSText(out.style.cssText);
    out.innerHTML = 
        "<b>⦁ CSS in #mystyle</b>: " + JSON.stringify(styRule) + "<br>" +
        "<b>⦁ CSS of #outcome</b>: " + JSON.stringify(outRule);
    console.log(styRule, outRule); /* Inspect result in the console. */
&#13;
<style id="mystyle">
.mybox1, /* a comment
    and new lines 
    to step up the game */
    .mybox 
{
    display: block; 
    width: 20px; height: 20px;
    background-color: /* a comment
        and a new line */ 
        rgb(204, 204, 204);
    -somebrowser-someproperty: somevalue;
}
</style>

<div id="outcome" style="
    display: block; padding: 0.5em;
    background-color: rgb(144, 224, 224);
">...</div>

<b style="color: red;">Also inspect the browser console.</b>
&#13;
&#13;
&#13;

答案 1 :(得分:6)

这是解析器的开始,可以做你想要的。当然它需要工作,特别是如果你想处理可能提供的任何通用CSS。这假设输入css是按照您提供的方式编写的,第一行是属性的名称,最后一行是'}',依此类推。

如果您不想只处理基本属性,编写复杂的解析器并不是一件容易的事。例如,如果您声明如下内容,那该怎么办?

input[type="text"],
table > tr:nth-child(2),
#link a:hover {
    -webkit-transition: width 2s; /* Safari and Chrome */
}

这是有效的CSS,但是如何从中提取有效的javascript变量名?如何将-webkit-transition转换为有意义的属性名称?整个任务闻起来就像你做错了。我没有在解析器上工作,而是在处理一个更稳定的解决方案。

顺便说一句,这是您可以从以下开始的代码:

    var s = '.mybox {\n';
    s += 'display: block;\n';
    s += 'width: 20px;\n';
    s += 'height: 20px;\n';
    s += 'background-color: rgb(204, 204, 204);\n';
    s += '}\n';

    // split css by line
    var css_rows = s.split('\n'); 

    // filter out empty elements and strip ';'      
    css_rows = css_rows.filter(function(x){ return x != '' }).map(function(x){ return x.trim().replace(';', '') });

    // create object
    var json_name = css_rows[0].trim().replace(/[\.\{\ \#]/g, '');
    eval('var ' + json_name + ' = {};');
    // remove first and last element
    css_rows = css_rows.splice(1, css_rows.length-2)

    for (elem in css_rows)
    {
        var elem_parts = css_rows[elem].split(':');
        var property_name = elem_parts[0].trim().replace('-', '');
        var property_value = elem_parts[1].trim();
        eval(json_name + '.' + property_name + ' = "' + property_value + '";');
    }

答案 2 :(得分:1)

如果CSS文档包含在html文档中,以便实际加载样式声明,您可以像这样在Javascript中逐步执行所有样式:

// Get all style sheet documents in this html document
var allSheets = document.styleSheets;

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

    // Get all CSS rules in the current style sheet document
    var rules = sheet.cssRules || sheet.rules;
    for (var j = 0; j < rules.length; ++j) {
        var rule = rules[j];

        // Get the selector definition ("div > p:first-child" for example)
        var selector = rule.selectorText;

        // Create an empty object to put the style definitions in
        var result = {};

        var style = rule.style;
        for (var key in style) {
            if (style.hasOwnProperty(key)) {
                result[key] = style.cssText;
            }
        }

        // At this point, you have the selector in the
        // selector variable (".mybox" for example)

        // You also have a javascript object in the
        // result variable, containing what you need.

        // If you need to output this as json, there
        // are several options for this.
    }
}

如果这不是您想要的,就像您要解析CSS文档并创建JavaScript源文件一样,您需要查看词法解析器,CSS文档对象模型,JSON序列化以及类似的东西......

答案 3 :(得分:0)

我在使用LeafLet尝试将CS​​S样式与JavaScript代码分开时遇到了同样的问题......我最终得到了这个:

local mod_arg = { }
for k, v in pairs(arg) do
    if v:find"'" then
      mod_arg[k] = '"'..v..'"'
    elseif v:find'[%s$`><|#]' then
      mod_arg[k] = "'"..v.."'"         
    else
      mod_arg[k] = v
    end
end 
local command = table.concat(mod_arg, ' ', -1, #mod_arg)
print(command)

这会产生这样的结果:

css to JavaScript object