4 votes

Fusionner des classes css avec jQuery/Javascript

J'ai un problème. J'ai une page web qui fait un usage intensif de plusieurs classes css.

<div class="class1 class2 class3">foo</div>

Malheureusement, j'ai un "navigateur" (à défaut d'un meilleur terme) qui ne peut pas gérer plusieurs classes css de cette manière.

Je peux identifier tous les éléments avec plusieurs classes mais je dois maintenant créer de nouvelles classes qui les fusionnent. La première tentative a été d'intégrer tous les styles dans l'attribut style, mais c'était beaucoup trop lent et cela a gonflé le document inutilement.

Ce que je veux faire maintenant, c'est trouver un élément avec plusieurs classes. Je crée une nouvelle classe qui est une combinaison, et je remplace la classe de l'élément par celle qui vient d'être créée, ainsi que tous les autres éléments ayant la même combinaison de classes.

Avez-vous des idées sur la meilleure façon d'aborder cette question ?

2voto

jfriend00 Points 152127

Passer en boucle toutes les étiquettes. Diviser les noms de classe en un tableau. Les trier pour les mettre dans un ordre prévisible. Réunir la chaîne de caractères.

$(document).ready(function() {
    var classList = {};
    $("*").each(function() {
        var temp;
        if (this.className) {
            temp = this.className.split(" "); // split into array
            temp.sort();                      // put in predictable order
            this.className = temp.join("");   // put class name back without spaces
            classList[this.className] = true; // add to list
        }
    });
    // classList object contains full list of all classNames used
});

À titre d'information, il semble vraiment étrange qu'un navigateur prenne en charge jQuery, mais ne prenne pas en charge les styles CSS pour les noms de classe multiples. Vous réalisez que vous allez devoir fournir des feuilles de style complètement différentes qui fonctionnent avec les noms concaténés, n'est-ce pas ? Et si vous pouvez modifier les feuilles de style, je me demande pourquoi vous ne pouvez pas modifier le code HTML.

Mise en œuvre opérationnelle : http://jsfiddle.net/jfriend00/uPET7/

1voto

Rob W Points 125904

Résumé : cette fonction renvoie une liste ordonnée de tous les noms de classes en double, qui peut facilement être utilisée pour fusionner des classes.

Pour commencer, procurez-vous un utile la liste des doublons :

var multi = {};

$("*[class]").each(function(){
    var class = this.className.replace(/^\s+|\s+$/g,"").replace(/\s+/g,".");
    if(!/\./.test(class)) return; //Ignore single classes
    if(multi[class]){
        multi[class]++;
    } else {
        multi[class] = 1;
    }
});

//Now, merge duplicates, because .class1.class2 == .class2.class1
var multi_nodup = {};
for(var classes in multi){
    var a_classes = classes.split(".");
    var a_classes = a_classes.sort();
    var a_classes = a_classes.join(".");
    if(multi_nodup[a_classes]){
        multi_nodup[a_classes] += multi[classes];
    } else {
        multi_nodup[a_classes] = multi[classes]
    }
}
//Now, multi_npdup is a map of all duplicate classnames

var array_multi = [];
for(var classes in multi_nodup){
    array_multi.push([multi_nodup[classes], classes]);
}
array_multi.sort(function(x,y){return y[0]-x[0]});
//array_multi is an array which looks like [["class1.class2.class2", 33],
//             ["class3.class4", 30], ...]
// = A list, consisting of multiple class names, where multiple classnames
// are shown, together with the nuber of occurences, sorted according to
// the frequence

Exécuter ma fonction et la variable de sortie array_multi . Vous obtiendrez ainsi une carte des noms de classes multiples, ce qui vous permettra de remplacer les noms de classes multiples en conséquence.

En raison de la façon particulière dont j'ai stocké les noms de classe, vous pouvez utiliser $("." + array_multi[n][0]) pour accéder à tous les éléments dont l'ensemble des noms de classe est égal à l'ensemble décrit à la section n ème position en array_multi .

Exemple de résultat lisible :

//Overwrites current document!
var list = "";
for(var i=0; i<array_multi.length; i++) list += array_multi[i][0] + "\t" + array_multi[i][1];
document.open();
document.write("<pre>"+list+"</pre>")
document.close();

Conversion automatique

Une façon d'automatiser la fusion des noms de classe est d'ajouter toutes les propriétés séparées des classes à une chaîne JavaScript, et de l'ajouter à un objet. C'est le moyen le plus fiable d'obtenir les propriétés CSS exactes, car si l'on tente d'obtenir les noms de classe par l'intermédiaire de la fonction document.styleSheets peut produire des résultats légèrement différents. Exemple :

var classStyle = {};
classStyle["class1"] = "border:1px solid #000;";
classStyle["class2"] = "color:red";

//Make sure that each declaration ends with a semicolon:
for(var i in classStyle) if(!/;$/.test(classStyle[i])) classStyle[i] += ";";

//Initialise
var all_styles = {};
for(var i=0; i<array_multi.length; i++){
    all_styles[array_multi[i][1]] = "";
}

//This loop takes definition precedence into account
for(var currentCName in classStyle){
    var currentClass = new RegExp("(?:^|\\.)" + currentCName + "(?:\\.|$)");

    // Rare occasion of failure: url("data:image/png,base64;....")
    var separateProps = classStyle[currentCName].split(";");
    var prop_RE = {};
    for(var p=0; p<separateProps.length; p++){
        var cssProperty = separateProps[p];
        if(!/:/.test(cssProperty)) continue; //Invalid CSS property
        prop_RE[cssProperty] = new RegExp("(^|;)\\s*" + cssProperty.match(/(\S+)\s*:/gi)[1] + "\\s*:[^;]+;?", "gi");
    }

    for(var class in all_styles){
        if(currentClass.test(class)){
            for(var k in prop_RE){
                all_styles[class] = all_styles[class].replace(prop_RE[k],"$1") + k;
            }
        }
    }
}

//To finish off:
var allClassesToString = "";
for(var class in all_styles){
    var newClass = class.replace(/\./g, "_");
    $("."+class).each(function(){
        this.className = newClass;
    });
    allClassesToString += "."+newClass + "{" + all_styles[class] + "}\n";
}

// allClassesToString <------- This variable now holds a string of all duplicate CSS classes!
//Example:
var style = $("<style>");
style.text(allClassesToString);
style.appendTo($("head:first"));

0voto

Andrew Points 8248

Cela ne semble pas insensé,

Bouclez chaque élément qui a plus d'une classe. Triez les classes (peu importe la manière tant qu'elle est cohérente) puis fusionnez-les pour créer la nouvelle classe. Conservez une liste de toutes les nouvelles classes css et vérifiez-les en cas de doublons.

Pour obtenir tous les styles d'un élément, voir aquí

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X