Плагин jQuery для работы с таблицами стилей.

Я прекрасно знаю, что у jQuery есть css()метод, который позволяет мне изменять элементы, указанные в стиле. Однако я хочу изменить правила в таблице стилей на ходу. У него есть некоторые законные применения, которые css()метод не может заменить.

Что-то вроде:

<style id="dyn-style">
    p{ color:black; }
</style>
<p>TEST</p>
<script>
    $('#dyn-style').getCssRule('p').alterRule('color', 'red');
</script>

Что затем меняет содержимое styleэлемента на это:

<style id="dyn-style">
    p{ color:red; }
</style>

Я немного искал, но нашел только это решение . Насколько я понимаю, он только добавляет новые styleэлементы (с определенными стилями), а не изменяет существующие.

У меня возникает соблазн написать плагин самостоятельно, но было бы бессмысленно делать это, если он уже существует.

Я не думаю, что вы можете сделать это в jQuery. Причина в том, что во многих браузерах javascript не может получить доступ ко всем таблицам стилей; вы получаете нарушение доступа для междоменного доступа и т. д. ... Но, если вы просто хотите возиться со встроенными <style>элементами, это было бы возможно, но это также довольно ограниченный плагин. ... Умный способ сделать что-то - это иметь один размещенный (и кэшированный) файл CSS с альтернативными классами. Затем jQuery добавляет и удаляет классы по желанию. Это также даст прирост производительности по сравнению с (пере) написанием стилей.

Ответы (1)

Я не смог найти такой плагин, поэтому написал свой собственный в стиле jquery . После того, как я закончил писать плагин, я хотел назвать его jQuery StyleSheet, но оказалось, что плагин с таким именем уже существует, и этот плагин делает именно то, что я хотел...

В любом случае другой плагин jQuery StyleSheet можно найти в репозитории jQuery и на GitHub .

Автор jQuery StyleSheet также упоминает некую утилиту YUI StyleSheet , которая может предложить сделать примерно то же самое.

Изменить: чтобы этот ответ не был единственной ссылкой, вот код моего плагина. Обратите внимание, что это опубликовано под лицензией WTFPL . Тут тоже могут быть баги...

(function($) {
    // cssNameToJsName(name) - Converts style name in css format to camel case format used by javascript
    //
    // background-color => backgroundColor
    function cssNameToJsName(name)
    {
        var split = name.split("-");
        var output = "";
        for(var i = 0; i < split.length; i++)
        {
            if (i > 0 && split[i].length > 0 && !(i == 1 && split[i] == "ms"))
            {
                split[i] = split[i].substr(0, 1).toUpperCase() + split[i].substr(1);
            }
            output += split[i];
        }
        return output;
    }

    // jsNameToCssName(name) - Converts style name in javascript camel case format to css format; NOT USED
    //
    // backgroundColor => background-color
    function jsNameToCssName(name)
    {
        return name.replace(/([A-Z])/g, "-$1").toLowerCase();
    }

    // Rule - Object storing list of rules within stylesheets matching (=) provided selector
    //
    // Fields:
    // length - number of rules in the list
    // [i] - a single rule within the list (indexing has no relation to the indexing within the stylesheet)
    //
    // Methods:
    // css() - Alters style within rules or returns the value of the first specified style within a rule
    // each() - executes provided function for all rules within the list
    // remove() - removes rules in the list
    //
    // new Rule (name, sheet) - creates a new list of rules matching provided selector
    // name - rule selector
    // sheet - list of styles (Sheet object)
    //
    // new Rule (name, sheet, index) - creates a new list of rules matching provided selector and matching provided index within the parent stylesheet
    // name - rule selector
    // sheet - list of styles (Sheet object)
    // index - index filter
    function Rule (name, sheet, index)
    {
        this.length = 0;
        var self = this;
        sheet.each(function()
        {
            // ie<9 hack
            var rules = null;
            if (typeof this.cssRules == 'undefined')
            {
                rules = this.rules;
            }
            else
            {
                rules = this.cssRules;
            }
            for (var i = 0; i < rules.length; i++)
            {
                if (rules[i].selectorText == name && (typeof index == 'undefined' || i == index))
                {
                    self[self.length] = rules[i]
                    self[self.length].index = i;
                    self.length++;
                }
            }
        });
    }

    // Alters style within rules or returns the value of the first specified style within a rule
    //
    // Rule.css(name) - returns value of specified style from the first rule in the list
    // name - style name in css format (for example "background-color")
    //
    // Example: $('#my-style').styleSheet().rule('p').css('color')
    //
    // Rule.css(name, value) - set specified style to provided value for all rules within the list
    // name - style name in css format
    // value - new value for specified style
    //
    // Example: $('#my-style').styleSheet().rule('p').css('color', 'red')
    //
    // Rule.css(name, value, index) - set specified style to provided value for rules matching provided index within the parent stylesheet
    // name - style name in css format
    // value - new value for specified style
    // index - rule index
    //
    // Example: $('#my-style').styleSheet().rule('p').css('color', 'red', 0)
    //
    // Rule.css(data) - set multiple styles for all rules in the list using an object (for example {'color' : 'red', 'font-weight' : 'bold'})
    // data - object containing style name and value pairs
    //
    // Example: $('#my-style').styleSheet().rule('p').css({'color' : 'red', 'font-weight' : 'bold'})
    //
    // Rule.css(data, index) - set multiple styles for all rules matching provided index within the parent stylesheet
    // data - object containing style name and value pairs
    // index - rule index
    //
    // Example: $('#my-style').styleSheet().rule('p').css({'color' : 'red', 'font-weight' : 'bold'}, 0)
    Rule.prototype.css = function() {
        var name = null;
        var data = null;
        var value = null;
        var index = null;
        // check function arguments to determine which where provided
        if (typeof arguments[0] == 'object')
        {
            data = arguments[0];
            if (arguments.length > 1)
            {
                index = arguments[1];
            }
        }
        else
        {
            name = arguments[0];
            if (arguments.length > 1)
            {
                value = arguments[1];
            }
            if (arguments.length > 2)
            {
                index = arguments[2];
            }
        }
        // check if set value or data was specified and if not return value of first matching style within the first rule in the list
        if (value == null && name != null)
        {
            if (this.lenght == 0)
                return null;

            return this[0].style[cssNameToJsName(name)];
        }
        // determin if we are setting multiple styles or just one
        if (data != null)
        {
            // if data object was provided, map its properties to styles
            this.each(function()
            {
                for (var key in data)
                {
                    // optional index filter
                    if (index == null || this.index == index)
                        this.style[cssNameToJsName(key)] = data[key]
                }
            });
        }
        else
        {
            // if name and value were provided, set them
            this.each(function()
            {
                // optional index filter
                if (index == null || this.index == index)
                    this.style[cssNameToJsName(name)] = value;
            });
        }
        return this;
    };

    // Rule.each(func) - executes provided function for all rules within the list
    // func - function to be executed
    Rule.prototype.each = function(func) {
        for(var i = 0; i < this.length; i++){
            func.apply(this[i], [this[i], i]);
        }
        return this;
    };

    // Rule.remove() - removes all rules in the list
    //
    // Rule.remove(index) - removes rules matching specified index within the parent stylesheet
    Rule.prototype.remove = function(index) {
        this.each(function()
        {
            if (typeof index == 'undefined' || this.index == index)
            {
                // ie<9 hack
                if (typeof this.parentStyleSheet.deleteRule == 'undefined')
                {
                    this.parentStyleSheet.removeRule(this.index);
                }
                else
                {
                    this.parentStyleSheet.deleteRule(this.index);
                }
            }
        });
    };

    // Sheet - Object storing list of stylesheets
    //
    // Fields:
    // elements - jquery style list of elements
    // length - number of stylesheets in the list
    // [i] - a single stylesheed within the list
    //
    // Methods:
    // each() - executes provided function for all rules within the list
    // rule() - returns a list of rules matching (=) provided selector within the stylesheet list
    // addRule() - adds a rule to stylesheets in the list
    //
    // new Sheet(elements) - creates a new stylesheet list from provided elements (element of type different than "style" will be ignored)
    // elements - jquery style list of elements
    //
    // Example: new Sheet($('style'))
    function Sheet (elements) {
        this.element = elements.find('style');
        this.length = 0;
        var self = this;
        elements.each(function()
        {
            self[self.length] = this.sheet;
            self.length++;
        });
    }

    // Sheet.rule() - returns list of rules with matching selector (=) from provided "style" elements (elements other than "style" are ignored)
    //
    // Sheet.rule(name) - returns list of rules with matching selector (=) from provided "style" elements
    // name - rule selector to match
    //
    // Example: $('#my-stylesheet').styleSheet().rule('p')
    //
    // Sheet.rule(name, index) - returns list of rules with matching selector (=) from provided "style" elements; also filtered by index within the parent stylesheet
    // name - rule selector to match
    // index - index within the parent stylesheet
    //
    // Example: $('#my-stylesheet').styleSheet().rule('p', 0)
    Sheet.prototype.rule = function(name, index) {
        return new Rule (name, this);
    };

    // Sheet.each(func) - executes provided function for all stylesheets within the list
    // func - function to be executed
    Sheet.prototype.each = function(func) {
        for(var i = 0; i < this.length; i++){
            func.apply(this[i], [this[i], i]);
        }
        return this;
    };

    // Sheet.addRule(name, style) - adds provided rule to all stylesheets in the list as the last rule in the stylesheet
    // name - rule selector
    // style - rule styles as a string or style name and value pair object
    //
    // Example: $('#my-stylesheet').styleSheet().addRule('p', 'color: red; font-weight: bold')
    // Example: $('#my-stylesheet').styleSheet().addRule('p', {'color': 'red', 'font-weight': 'bold'})
    //
    // Rule.addRule(name, style, index) - inserts provided rule to all stylesheets in the list in specified position
    // name - rule selector
    // style - rule styles as a string or style name and value pair object
    // index - position of the inserted rule within the stylesheet
    Sheet.prototype.addRule = function(name, style, index) {
        this.each(function()
        {
            var oldIe = typeof this.cssRules == 'undefined';
            if (typeof index == 'undefined')
            {
                // ie<9 hack
                var rules = null;
                if (oldIe)
                {
                    rules = this.rules;
                }
                else
                {
                    rules = this.cssRules;
                }
                index = rules.length;
            }
            var styleStr = "";
            if (typeof style == 'object')
            {
                for (var key in style)
                {
                    styleStr += key + ": " + style[key] + ";";
                }
            }
            else
            {
                styleStr = style;
            }
            if (oldIe)
            {
                this.addRule(name, styleStr, index);
            }
            else
            {
                styleStr = name + " {" + styleStr + "}";
                this.insertRule(styleStr, index);
            }
        });
        return this;
    };

    // styleSheet - returns list of stylesheets ("style" elements) from within the provided elements
    //
    // Example: $('#my-stylesheet').styleSheet()
    $.fn.styleSheet = function() {
        return new Sheet (this);
    };

    // wrapper for styleSheet().rule(name, index)
    $.fn.cssRule = function(name, index) {
        return styleSheet().rule(name, index);
    };

    // wrapper for styleSheet().addRule(name, style, index)
    $.fn.addCssRule = function(name, style, index) {
        return styleSheet().addRule(name, style, index);
    };

    // wrapper for styleSheet().rule(name, index).remove();
    $.fn.removeCssRule = function(name, index) {
        return styleSheet().rule(name, index).remove();
    };
})(jQuery);