【问题标题】:Convert CSS-Object to Style Tag将 CSS 对象转换为样式标签
【发布时间】: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);

我用谷歌搜索和 stackoverflowed,但找不到将我的 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 } );

【问题讨论】:

    标签: javascript jquery html css typescript


    【解决方案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:before{content: '123'}的引用
    • 单引号不是有效的 JSON,我猜它可能被解析为数字。但实际上不确定。
    猜你喜欢
    • 1970-01-01
    • 2015-04-20
    • 2016-06-16
    • 2017-12-25
    • 2019-09-24
    • 2021-05-11
    • 2020-02-09
    • 1970-01-01
    • 2011-01-14
    相关资源
    最近更新 更多