将 CSS 对象转换为样式标签

Posted

技术标签:

【中文标题】将 CSS 对象转换为样式标签【英文标题】:Convert CSS-Object to Style Tag 【发布时间】:2017-05-09 06:18:02 【问题描述】:

有时我不得不以编程方式将 CSS 样式添加到 DOM(如果你需要一个理由:想象一下编写一个带有自己的样式但应该只包含一个 *.js 文件的小型 ui 小部件以便更轻松处理)。在这种情况下,我更喜欢在我的脚本代码中使用对象表示法定义样式,而不是一个混合规则、属性和标记的大字符串。

var thumbHoverStyle = 
    "background-color": "rgba(211, 211, 211, 0.5)",
    "cursor": "pointer"
;

var thumbHoverStyle = "<style> .thumb:hover  background-color: rgba(211, 211, 211, 0.5); cursor: pointer;  </style>";

这样的 css 对象可以很容易地与 JQuery's .css() function 一起使用,但是一旦我想设置 css pseudo-class 的样式(在我的示例中为:hover),麻烦就开始了。在这种情况下,我不能使用 JQuery .css() 函数,我只能在我的 DOM 中插入相应的样式标签。

var thumbHoverStyleTag = toStyleTag(  ".thumb:hover": thumbHoverStyle  );
_root.append(thumbHoverStyleTag);

我用谷歌搜索和 ***ed,但找不到将我的 css 对象转换为样式标签的实用程序函数。 最后我写了自己的函数(我可能会提供它作为这个问题的答案),但我仍然想知道是否有一个库函数。 实现此目的最优雅的方法是什么?

编辑

我在 TypeScript 中的实现:

function appendPxIfNumber(value: any): string

    return (typeof value === "number") ? "" + value + "px" : value;


function toStyleTag(rulesObj: any)

    var combinedRules: string = "";
    for (var selector in rulesObj)
    
        var cssObject = rulesObj[selector];
        var combinedProperties = "";
        for (var prop in cssObject) 
            var value = cssObject[prop];
            combinedProperties += `$prop: $appendPxIfNumber(value);` + "\n";
        
        combinedRules += ` $selector $combinedProperties` + "\n";
    
    return $(`<style>$combinedRules</style>`);

使用示例:

var styleTag = toStyleTag(  ".thumb": thumbStyle, ".thumb:hover": thumbHoverStyle  );

【问题讨论】:

【参考方案1】:

我想再试一次,因为这是一个有趣的问题。

这是我整理的原生 javascript 解决方案:

var thumbStyle = 
    "width" : "100px",
    "height" : "100px",
    "text-align" : "center",
    "line-height" : "100px",
    "background-color": "rgb(211, 211, 211)"
;

var thumbHoverStyle = 
    "color" : "rgb(255,255,255)",
    "background-color": "rgb(255, 0, 0)",
    "cursor": "pointer"
;

var dynamicStyle = document.createElement('style');
document.head.appendChild(dynamicStyle);
var dynamicStyleSheet = dynamicStyle.sheet;

function addStyles(selector, cssStyleObject) 
    var properties = Object.keys(cssStyleObject);
    properties.forEach(function(property)
        var value = cssStyleObject[property];
      
        var dynamicRule = selector + ' ' + property + ': ' + value + ';';
      
        dynamicStyleSheet.insertRule(dynamicRule, dynamicStyleSheet.cssRules.length);
    );


// Add styles dynamically by stating a selector and the name of a CSS Style Object

addStyles('div', thumbStyle);
addStyles('div:hover', thumbHoverStyle);
&lt;div&gt;Hover Me&lt;/div&gt;

【讨论】:

不确定它是否真的很重要,但这样您将为样式中的每个属性生成并添加一个新规则,而不是一个具有 n 个属性的规则。 我不确定我是否遵循 - 请您再次解释一下吗?谢谢。 据我了解,您生成的 css 看起来像:.foo color: red; .foo background-color: white; .foo margin-left: 2px; .foo margin-right: 4px; 而不是 .foo color: red; background-color: white; margin-left: 2px; margin-right: 4px; 啊,是的,我明白了——我明白你的意思。不过修复起来相当简单。您可以将var dynamicRule = selector + ' ' 的声明移到forEach 循环上方,然后循环通过dynamicRule += property + ': ' + value + '; '【参考方案2】:

我很想:

mouseover() 上添加thumbHoverStyle CSS 对象;和 在mouseout() 上用thumbDefaultStyle CSS 对象替换它

var thumbStyle = 
    "width" : "100px",
    "height" : "100px",
    "text-align" : "center",
    "line-height" : "100px",
    "background-color": "rgb(211, 211, 211)"
;

var thumbHoverStyle = 
    "color" : "rgb(255,255,255)",
    "background-color": "rgb(255, 0, 0)",
    "cursor": "pointer"
;

var thumbDefaultStyle = 
    "color" : "rgb(0,0,0)",
    "background-color": "rgb(211, 211, 211)",
    "cursor": "default"
;

$(document).ready(function()

    $('div').css(thumbStyle);

    $('input[type="checkbox"]').change(function()

        if ($('input[type="checkbox"]').prop('checked')) 

            $('div').mouseover(function()
                $(this).css(thumbHoverStyle);
            );

            $('div').mouseout(function()
                $(this).css(thumbDefaultStyle);
            );
        

        else 

            $('div').mouseover(function()
                $(this).css(thumbDefaultStyle);
            );

            $('div').mouseout(function()
                $(this).css(thumbDefaultStyle);
            );
        
    );
);
div, button 
display: inline-block;
margin-right: 24px;
vertical-align: top;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div>Hover Me</div>
<input type="checkbox" />Activate New Hover Behaviour

【讨论】:

感谢您提出的解决方案。但是我还有其他理由要找到我的问题中描述的转换器功能。 :hover 类只是一个例子。我宁愿让浏览器的渲染引擎处理元素的悬停视觉状态,也不愿编写 mouseIn/mouseOut 处理程序代码来模拟 css :hover.【参考方案3】:

我的函数 toStyleTag() 背后的方法是它首先使用 for...in statement 迭代 styleTag 并检查 styleTag hasOwnProperty() 是否是 selector。然后我reduce() 通过在对象上执行Object.keys() 返回的数组styleTag[selector],我通过加入currentValue(属性)和styleTag[selector][currentValue]](规则)来concat()accumulator: 分开。这样做可以让styles 成为property: rule 形式的字符串数组。现在这是我们需要使用insertRule() 的格式,我们使用它来将新的CSS 规则插入到当前样式表中。请注意,我正在抓取 cssRules 的长度以找到索引 + 1,以便我们可以在样式表的最后插入这条新规则,以确保它不会被覆盖。

var styleSheet = document.styleSheets[0];

function toStyleTag(styleTag) 
  for(var selector in styleTag) 
    if(styleTag.hasOwnProperty(selector)) 
      let styles = Object.keys(styleTag[selector]).reduce(function(accumulator, currentValue) 
        return accumulator.concat([currentValue, styleTag[selector][currentValue]].join(':'));
      , []);
      styleSheet.insertRule(selector + '' + styles.join(';') + '', styleSheet.cssRules.length);
    
  


var thumbHoverStyle = 
  'background-color': 'rgba(211, 211, 211, 0.5)',
  'cursor': 'pointer'
;

toStyleTag( '.thumb:hover': thumbHoverStyle );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="thumb">
  <img src="http://placehold.it/350x350">
</div>

【讨论】:

不错。我的toStyleTag() 函数也类似,使用for..in 循环遍历输入,并将各个部分一一连接。【参考方案4】:

这是一个适用于原始样式对象的工作示例: 我会将JSON 转换为CSS。并定义一个应该设置样式的目标请记住,没有应该设置样式的选择器......所以我添加了一个targetSelector

var targetSelector='.thumb:hover',
    styleObj = 
      "background-color": "rgba(211, 211, 211, 0.5)",
      "cursor": "pointer"
    ,

    // Convert the JSON into CSS
    styleTagContent = JSON.stringify(styleObj,null,'\t')
                          .replace(/"/g,'')
                          .replace(/,\n/g,';')
                          .replace(/\/g, ';')  



  $('<style>'+targetSelector+styleTagContent+'</style>').appendTo('head');

这是一个有效的Plunk,看看它是如何工作的。

【讨论】:

哦,太好了,我还没有想过使用JSON stringify 将我的css-object 转换为css 字符串。 你的方法会去掉a:beforecontent: '123'的引用 单引号不是有效的 JSON,我猜它可能被解析为数字。但实际上不确定。

以上是关于将 CSS 对象转换为样式标签的主要内容,如果未能解决你的问题,请参考以下文章

将外部 CSS 转换为内联 CSS 用于 Rails 中的邮件

初识jQuery

什么是回流与重绘

CSS标签显示模式 ③ ( 标签显示模式转换 | 行内元素转换为块级元素 | 块级元素转换为行内元素 | 块级元素行内元素转换为行内块元素 )

CSS 到 JSON 解析器或转换器

如何将从 Chrome 复制的 css 选择器路径转换为 ​​beautifulsoup 对象?