web-dev-qa-db-fra.com

le plugin CSS jQuery qui retourne le style calculé de l’élément à pseudo-cloner cet élément?

Je cherche un moyen d'utiliser jQuery pour renvoyer un objet de styles calculés pour le premier élément correspondant. Je pourrais ensuite passer cet objet à un autre appel de la méthode CSS de jQuery.

Par exemple, avec width , je peux procéder comme suit pour que les 2 divs aient la même largeur:

$('#div2').width($('#div1').width());

Ce serait bien si je pouvais faire en sorte que la saisie de texte ressemble à une étendue existante:

$('#input1').css($('#span1').css());

où .css () sans argument renvoie un objet pouvant être passé à .css (obj) .

(Je ne trouve pas de plugin jQuery pour cela, mais il semble qu'il devrait exister. S'il n'existe pas, je transformerai le mien ci-dessous en plugin et le posterai avec toutes les propriétés que j'utilise.) 

En gros, je veux pseudo-cloner certains éléments mais utiliser une balise différente. Par exemple, j'ai un élément li que je veux masquer et un élément d'entrée qui lui est identique. Lorsque l'utilisateur tape , il semble qu'ils soient en train de modifier l'élément inline.

Je suis également ouvert à d'autres approches pour résoudre ce problème de pseudo-clonage. Aucune suggestion?

Voici ce que j'ai actuellement. Le seul problème est d’obtenir tous les styles possibles. Cela pourrait être une liste ridiculement longue.


jQuery.fn.css2 = jQuery.fn.css;
jQuery.fn.css = function() {
    if (arguments.length) return jQuery.fn.css2.apply(this, arguments);
    var attr = ['font-family','font-size','font-weight','font-style','color',
    'text-transform','text-decoration','letter-spacing','Word-spacing',
    'line-height','text-align','vertical-align','direction','background-color',
    'background-image','background-repeat','background-position',
    'background-attachment','opacity','width','height','top','right','bottom',
    'left','margin-top','margin-right','margin-bottom','margin-left',
    'padding-top','padding-right','padding-bottom','padding-left',
    'border-top-width','border-right-width','border-bottom-width',
    'border-left-width','border-top-color','border-right-color',
    'border-bottom-color','border-left-color','border-top-style',
    'border-right-style','border-bottom-style','border-left-style','position',
    'display','visibility','z-index','overflow-x','overflow-y','white-space',
    'clip','float','clear','cursor','list-style-image','list-style-position',
    'list-style-type','marker-offset'];
    var len = attr.length, obj = {};
    for (var i = 0; i < len; i++) 
        obj[attr[i]] = jQuery.fn.css2.call(this, attr[i]);
    return obj;
}

Edit: J'utilise le code ci-dessus depuis un moment. Cela fonctionne bien et se comporte exactement comme la méthode css d'origine à une exception près: si 0 arguments sont passés, cela renvoie l'objet de style calculé. 

Comme vous pouvez le constater, il appelle immédiatement la méthode css originale si tel est le cas. Sinon, il obtient les styles calculés de toutes les propriétés répertoriées (rassemblés à partir de la liste de styles calculée de Firebug). Bien que la liste de valeurs soit longue, c'est assez rapide. J'espère que c'est utile pour les autres.

67
Keith Bentrup

Deux ans de retard, mais j'ai la solution que vous recherchez. Voici un plugin que j'ai écrit (en enveloppant la fonction d'un autre gars au format plugin) qui fait exactement ce que vous voulez, mais obtient tout styles possibles dans tous les navigateurs, même IE.

jquery.getStyleObject.js:

/*
 * getStyleObject Plugin for jQuery JavaScript Library
 * From: http://upshots.org/?p=112
 *
 * Copyright: Unknown, see source link
 * Plugin version by Dakota Schneider (http://hackthetruth.org)
 */

(function($){
    $.fn.getStyleObject = function(){
        var dom = this.get(0);
        var style;
        var returns = {};
        if(window.getComputedStyle){
            var camelize = function(a,b){
                return b.toUpperCase();
            }
            style = window.getComputedStyle(dom, null);
            for(var i=0;i<style.length;i++){
                var prop = style[i];
                var camel = prop.replace(/\-([a-z])/g, camelize);
                var val = style.getPropertyValue(prop);
                returns[camel] = val;
            }
            return returns;
        }
        if(dom.currentStyle){
            style = dom.currentStyle;
            for(var prop in style){
                returns[prop] = style[prop];
            }
            return returns;
        }
        return this.css();
    }
})(jQuery);

L'utilisation de base est assez simple:

var style = $("#original").getStyleObject(); // copy all computed CSS properties
$("#original").clone() // clone the object
    .parent() // select it's parent
    .appendTo() // append the cloned object to the parent, after the original
                // (though this could really be anywhere and ought to be somewhere
                // else to show that the styles aren't just inherited again
    .css(style); // apply cloned styles

J'espère que cela pourra aider.

59
Dakota

Ce n'est pas jQuery mais, dans Firefox, Opera et Safari, vous pouvez utiliser window.getComputedStyle(element) pour obtenir les styles calculés pour un élément et dans IE <= 8, vous pouvez utiliser element.currentStyle. Les objets renvoyés sont différents dans chaque cas, et je ne suis pas certain que les éléments et les styles créés à l'aide de JavaScript fonctionnent correctement, mais ils seront peut-être utiles.

Dans Safari, vous pouvez effectuer les opérations suivantes:

document.getElementById('b').style.cssText = window.getComputedStyle(document.getElementById('a')).cssText;
22
Richard M

Je ne sais pas si vous êtes satisfait des réponses que vous avez obtenues jusqu'à présent mais je ne l'étais pas et les miennes ne vous plairaient peut-être pas non plus, mais cela pourrait aider quelqu'un d'autre. 

Après avoir réfléchi à la manière de "cloner" ou "copier" les styles des éléments de l'un à l'autre, je me suis rendu compte que ce n'était pas très optimal de faire une boucle pour n et de l'appliquer à n2, mais nous sommes un peu coincés avec cela .

Lorsque vous vous trouvez confronté à ces problèmes, il est rarement nécessaire de copier TOUS les styles d'un élément à un autre ... vous avez généralement une raison spécifique de vouloir appliquer "certains" styles.

Voici ce que je suis revenu à:

$.fn.copyCSS = function( style, toNode ){
  var self = $(this);
  if( !$.isArray( style ) ) style=style.split(' ');
  $.each( style, function( i, name ){ toNode.css( name, self.css(name) ) } );
  return self;
}

Vous pouvez lui transmettre une liste d'attributs CSS séparés par des espaces comme premier argument et le noeud sur lequel vous souhaitez les cloner comme deuxième argument, comme suit:

$('div#copyFrom').copyCSS('width height color',$('div#copyTo'));

Quoi que ce soit qui semble "se désaligner" après cela, je vais essayer de régler le problème avec des feuilles de style afin de ne pas encombrer mes Js avec trop d'idées ratées.

5
Quickredfox

Maintenant que j'ai eu le temps d'examiner le problème et de mieux comprendre le fonctionnement de la méthode CSS interne de jQuery, ce que j'ai posté semble fonctionner assez bien pour le cas d'utilisation que j'ai mentionné. 

Il a été proposé que vous puissiez résoudre ce problème avec CSS, mais je pense que c'est une solution plus généralisée qui fonctionnera dans tous les cas sans avoir à ajouter des classes de suppression ou mettre à jour vos fichiers CSS.

J'espère que d'autres le trouveront utile. Si vous trouvez un bug, s'il vous plaît faites le moi savoir.

4
Keith Bentrup

J'aime votre réponse Quickredfox. J'avais besoin de copier un peu de CSS mais pas tout de suite, donc je l'ai modifié pour rendre le "toNode" facultatif.

$.fn.copyCSS = function( style, toNode ){
  var self = $(this),
   styleObj = {},
   has_toNode = typeof toNode != 'undefined' ? true: false;
 if( !$.isArray( style ) ) {
  style=style.split(' ');
 }
  $.each( style, function( i, name ){ 
  if(has_toNode) {
   toNode.css( name, self.css(name) );
  } else {
   styleObj[name] = self.css(name);
  }  
 });
  return ( has_toNode ? self : styleObj );
}

Si vous appelez ça comme ça:

$('div#copyFrom').copyCSS('width height color');

Ensuite, il retournera un objet avec vos déclarations CSS que vous pourrez utiliser plus tard:

{
 'width': '140px',
 'height': '860px',
 'color': 'rgb(238, 238, 238)'
}

Merci pour le point de départ.

3
HexInteractive

Multifonction .css()

Usage

$('body').css();        // -> { ... } - returns all styles
$('body').css('*');     // -> { ... } - the same (more verbose)
$('body').css('color width height')  // -> { color: .., width: .., height: .. } - returns requested styles
$('div').css('width height', '100%')  // set width and color to 100%, returns self
$('body').css('color')  // -> '#000' - native behaviour

Code

(function($) {

    // Monkey-patching original .css() method
    var nativeCss = $.fn.css;

    var camelCase = $.camelCase || function(str) {
        return str.replace(/\-([a-z])/g, function($0, $1) { return $1.toUpperCase(); });
    };

    $.fn.css = function(name, value) {
        if (name == null || name === '*') {
            var elem = this.get(0), css, returns = {};
            if (window.getComputedStyle) {
                css = window.getComputedStyle(elem, null);
                for (var i = 0, l = css.length; i < l; i++) {
                    returns[camelCase(css[i])] = css.getPropertyValue(css[i]);
                }
                return returns;
            } else if (elem.currentStyle) {
                css = elem.currentStyle;
                for (var prop in css) {
                    returns[prop] = css[prop];
                }
            }
            return returns;
        } else if (~name.indexOf(' ')) {
            var names = name.split(/ +/);
            var css = {};
            for (var i = 0, l = names.length; i < l; i++) {
                css[names[i]] = nativeCss.call(this, names[i], value);
            }
            return arguments.length > 1 ? this : css;
        } else {
            return nativeCss.apply(this, arguments);
        }
    }

})(jQuery);

L'idée principale est tirée de Dakota & HexInteractive's answers.

3
disfated

Grande fonction fournie par l'OP. Je l'ai légèrement modifié pour que vous puissiez choisir les valeurs que vous voulez renvoyer.

(function ($) {
    var jQuery_css = $.fn.css,
        gAttr = ['font-family','font-size','font-weight','font-style','color','text-transform','text-decoration','letter-spacing','Word-spacing','line-height','text-align','vertical-align','direction','background-color','background-image','background-repeat','background-position','background-attachment','opacity','width','height','top','right','bottom','left','margin-top','margin-right','margin-bottom','margin-left','padding-top','padding-right','padding-bottom','padding-left','border-top-width','border-right-width','border-bottom-width','border-left-width','border-top-color','border-right-color','border-bottom-color','border-left-color','border-top-style','border-right-style','border-bottom-style','border-left-style','position','display','visibility','z-index','overflow-x','overflow-y','white-space','clip','float','clear','cursor','list-style-image','list-style-position','list-style-type','marker-offset'];
    $.fn.css = function() {
        if (arguments.length && !$.isArray(arguments[0])) return jQuery_css.apply(this, arguments);
        var attr = arguments[0] || gAttr,
            len = attr.length,
            obj = {};
        for (var i = 0; i < len; i++) obj[attr[i]] = jQuery_css.call(this, attr[i]);
        return obj;
    }
})(jQuery);

Choisissez les valeurs que vous voulez en spécifiant votre propre tableau: $().css(['width','height']);

2
Shea

Je voulais juste ajouter une extension au code soumis par Dakota.

Si vous voulez cloner un élément avec tous les styles qui lui sont appliqués et tous les éléments enfants, vous pouvez utiliser le code suivant:

/*
 * getStyleObject Plugin for jQuery JavaScript Library
 * From: http://upshots.org/?p=112
 *
 * Copyright: Unknown, see source link
 * Plugin version by Dakota Schneider (http://hackthetruth.org)
 */

(function($){
    $.fn.getStyleObject = function(){
        var dom = this.get(0);
        var style;
        var returns = {};
        if(window.getComputedStyle){
            var camelize = function(a,b){
                return b.toUpperCase();
            }
            style = window.getComputedStyle(dom, null);
            for(var i=0;i<style.length;i++){
                var prop = style[i];
                var camel = prop.replace(/\-([a-z])/g, camelize);
                var val = style.getPropertyValue(prop);
                returns[camel] = val;
            }
            return returns;
        }
        if(dom.currentStyle){
            style = dom.currentStyle;
            for(var prop in style){
                returns[prop] = style[prop];
            }
            return returns;
        }
        return this.css();
    }


    $.fn.cloneWithCSS = function() {
        styles = {};

        $this = $(this);
        $clone = $this.clone();
        $clone.css( $this.getStyleObject() );

        children = $this.children().toArray();
        var i = 0;
        while( children.length ) {
            $child = $( children.pop() );
            styles[i++] = $child.getStyleObject();
            $child.children().each(function(i, el) {
                children.Push(el);
            })
        }

        cloneChildren = $clone.children().toArray()
        var i = 0;
        while( cloneChildren.length ) {
            $child = $( cloneChildren.pop() );
            $child.css( styles[i++] );
            $child.children().each(function(i, el) {
                cloneChildren.Push(el);
            })
        }

        return $clone
    }

})(jQuery);

Ensuite, vous pouvez juste faire: $clone = $("#target").cloneWithCSS()

2
Nonconformist
$.fn.cssCopy=function(element,styles){
var self=$(this);
if(element instanceof $){
    if(styles instanceof Array){
        $.each(styles,function(val){
            self.css(val,element.css(val));
        });
    }else if(typeof styles===”string”){
        self.css(styles,element.css(styles));
    }
}
return this;
};

Exemple d'utilisation

$("#element").cssCopy($("#element2"),['width','height','border'])
0
rterrani