web-dev-qa-db-fra.com

Transformez un nombre en nombre d'étoiles à l'aide de jQuery et CSS

J'examinais jquery plugin et je me demandais comment l'adapter pour transformer un nombre (comme 4.8618164) en un 4.8618164 étoiles remplies sur 5. Interpréter un nombre <5 en étoiles remplies dans un système d'évaluation à 5 étoiles avec jQuery/JS/CSS. 

Notez que ceci affichera/affichera uniquement les notes attribuées par un nombre déjà disponible et n'acceptera pas les nouvelles soumissions de notes. 

98
Steve

Voici une solution pour vous, utilisant une seule image très petite et simple et un élément span généré automatiquement:

CSS

span.stars, span.stars span {
    display: block;
    background: url(stars.png) 0 -16px repeat-x;
    width: 80px;
    height: 16px;
}

span.stars span {
    background-position: 0 0;
}

Image

_ { alt text http://www.ulmanen.fi/stuff/stars.png } _

Remarque: ne PAS un lien hypertexte vers l'image ci-dessus! Copiez le fichier sur votre propre serveur et utilisez-le à partir de là.

jQuery

$.fn.stars = function() {
    return $(this).each(function() {
        // Get the value
        var val = parseFloat($(this).html());
        // Make sure that the value is in 0 - 5 range, multiply to get width
        var size = Math.max(0, (Math.min(5, val))) * 16;
        // Create stars holder
        var $span = $('<span />').width(size);
        // Replace the numerical value with stars
        $(this).html($span);
    });
}

Si vous souhaitez limiter les étoiles à une taille de demi-étoile ou de quart, ajoutez l'une de ces lignes avant la ligne var size:

val = Math.round(val * 4) / 4; /* To round to nearest quarter */
val = Math.round(val * 2) / 2; /* To round to nearest half */

HTML

<span class="stars">4.8618164</span>
<span class="stars">2.6545344</span>
<span class="stars">0.5355</span>
<span class="stars">8</span>

Usage

$(function() {
    $('span.stars').stars();
});

Sortie

_ { Image du jeu d'icônes de fugue (www.pinvoke.com) http://www.ulmanen.fi/stuff/stars_output.png } _

Démo

_ { http://www.ulmanen.fi/stuff/stars.php } _

Cela conviendra probablement à vos besoins. Avec cette méthode, vous n'avez pas à calculer les largeurs d'étoiles de trois-quarts ou autres, vous devez simplement lui donner un flotteur et cela vous donnera vos étoiles.


Une petite explication sur la façon dont les étoiles sont présentées pourrait être en ordre.

Le script crée deux éléments d’étendue au niveau des blocs. Les deux étendues ont initialement une taille de 80 pixels * 16 pixels et une image de fond stars.png. Les étendues sont imbriquées, de sorte que la structure des étendues ressemble à ceci:

<span class="stars">
    <span></span>
</span>

L'envergure externe reçoit un background-position de 0 -16px. Cela rend les étoiles grises dans l'envergure extérieure visibles. Comme l'envergure extérieure a une hauteur de 16px et repeat-x, il ne montrera que 5 étoiles grises.

L’envergure interne, quant à elle, a un background-position de 0 0 qui ne rend visibles que les étoiles jaunes.

Cela fonctionnerait bien sûr avec deux fichiers image distincts, star_yellow.png et star_gray.png. Mais comme les étoiles ont une hauteur fixe, nous pouvons facilement les combiner en une seule image. Ceci utilise la technique Sprite CSS .

À présent que les plages sont imbriquées, elles se superposent automatiquement. Dans le cas par défaut, lorsque la largeur des deux étendues est de 80 pixels, les étoiles jaunes masquent complètement les étoiles grises.

Mais lorsque nous ajustons la largeur de la largeur intérieure, la largeur des étoiles jaunes diminue, révélant les étoiles grises.

En ce qui concerne l’accessibilité, il aurait été plus sage de laisser le nombre à virgule dans l’espace intérieur et de le masquer avec text-indent: -9999px, afin que les personnes dont le CSS est désactivé verraient au moins le nombre à virgule flottante à la place des étoiles.

Espérons que cela ait du sens.


Mise à jour 2010/10/22

Maintenant encore plus compact et difficile à comprendre! Peut aussi être réduit à une doublure:

$.fn.stars = function() {
    return $(this).each(function() {
        $(this).html($('<span />').width(Math.max(0, (Math.min(5, parseFloat($(this).html())))) * 16));
    });
}
253
Tatu Ulmanen

Si vous devez seulement supporter les navigateurs modernes, vous pouvez vous en tirer avec:

  • Non images;
  • Principalement statique css;
  • Nearly no jQuery ou Javascript;

Il vous suffit de convertir le nombre en class, par exemple. class='stars-score-50'.

Tout d'abord une démonstration du balisage "rendu":

body { font-size: 18px; }

.stars-container {
  position: relative;
  display: inline-block;
  color: transparent;
}

.stars-container:before {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: lightgray;
}

.stars-container:after {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: gold;
  overflow: hidden;
}

.stars-0:after { width: 0%; }
.stars-10:after { width: 10%; }
.stars-20:after { width: 20%; }
.stars-30:after { width: 30%; }
.stars-40:after { width: 40%; }
.stars-50:after { width: 50%; }
.stars-60:after { width: 60%; }
.stars-70:after { width: 70%; }
.stars-80:after { width: 80%; }
.stars-90:after { width: 90%; }
.stars-100:after { width: 100; }
Within block level elements:

<div><span class="stars-container stars-0">★★★★★</span></div>
<div><span class="stars-container stars-10">★★★★★</span></div>
<div><span class="stars-container stars-20">★★★★★</span></div>
<div><span class="stars-container stars-30">★★★★★</span></div>
<div><span class="stars-container stars-40">★★★★★</span></div>
<div><span class="stars-container stars-50">★★★★★</span></div>
<div><span class="stars-container stars-60">★★★★★</span></div>
<div><span class="stars-container stars-70">★★★★★</span></div>
<div><span class="stars-container stars-80">★★★★★</span></div>
<div><span class="stars-container stars-90">★★★★★</span></div>
<div><span class="stars-container stars-100">★★★★★</span></div>

<p>Or use it in a sentence: <span class="stars-container stars-70">★★★★★</span> (cool, huh?).</p>

Puis une démo qui utilise un tout petit peu de code:

$(function() {
  function addScore(score, $domElement) {
    $("<span class='stars-container'>")
      .addClass("stars-" + score.toString())
      .text("★★★★★")
      .appendTo($domElement);
  }

  addScore(70, $("#fixture"));
});
body { font-size: 18px; }

.stars-container {
  position: relative;
  display: inline-block;
  color: transparent;
}

.stars-container:before {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: lightgray;
}

.stars-container:after {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: gold;
  overflow: hidden;
}

.stars-0:after { width: 0%; }
.stars-10:after { width: 10%; }
.stars-20:after { width: 20%; }
.stars-30:after { width: 30%; }
.stars-40:after { width: 40%; }
.stars-50:after { width: 50%; }
.stars-60:after { width: 60%; }
.stars-70:after { width: 70%; }
.stars-80:after { width: 80%; }
.stars-90:after { width: 90%; }
.stars-100:after { width: 100; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Generated: <div id="fixture"></div>

Les principaux inconvénients de cette solution sont les suivants:

  1. Vous avez besoin des étoiles à l'intérieur de l'élément pour générer la largeur correcte;
  2. Il n'y a pas de balisage sémantique, par exemple vous préféreriez le score en tant que texte à l'intérieur de l'élément;
  3. Cela permet seulement autant de partitions que vous aurez de classes (parce que nous ne pouvons pas utiliser Javascript pour définir une width précise sur un pseudo-élément).

Pour résoudre ce problème, la solution ci-dessus peut être facilement modifiée. Les bits :before et :after doivent devenir des éléments réels dans le DOM (nous avons donc besoin de JS pour cela).

Ce dernier est laissé comme un exercice pour le lecteur.

25
Jeroen

Essayez cette fonction jQuery

<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet">

<span class="stars" data-rating="4" data-num-stars="5" ></span>

<script>
    $.fn.stars = function() {
        return $(this).each(function() {

            var rating = $(this).data("rating");

            var numStars = $(this).data("numStars");

            var fullStar = new Array(Math.floor(rating + 1)).join('<i class="fa fa-star"></i>');

            var halfStar = ((rating%1) !== 0) ? '<i class="fa fa-star-half-empty"></i>': '';

            var noStar = new Array(Math.floor(numStars + 1 - rating)).join('<i class="fa fa-star-o"></i>');

            $(this).html(fullStar + halfStar + noStar);

        });
    }

    $('.stars').stars();

 Screenshot

FontAwesome CSS

Vous pouvez télécharger FontAwesome sur http://fontawesome.io/

18
Rajasekar D

Pourquoi ne pas simplement avoir cinq images distinctes d’une étoile (vides, quartes pleines, demi-pleines, pleines trois-quarts et pleines) puis injecter les images dans votre DOM en fonction de la valeur de notation tronquée ou arrondie multipliée par 4 obtenir un nombre entier pour les trimestres)?

Par exemple, 4,8618164 multiplié par 4 et arrondi est 19, ce qui correspond à quatre et trois étoiles.

Sinon (si vous êtes paresseux comme moi), choisissez une seule image parmi 21 (0 étoiles sur 5 étoiles, par incréments d’un quart) et sélectionnez une seule image en fonction de la valeur susmentionnée. Ensuite, il ne s'agit que d'un calcul suivi d'un changement d'image dans le DOM (plutôt que d'essayer de modifier cinq images différentes).

7
paxdiablo

Je me suis retrouvé totalement dépourvu de JS pour éviter les retards de rendu côté client. Pour ce faire, je génère du HTML comme ceci:

<span class="stars" title="{value as decimal}">
    <span style="width={value/5*100}%;"/>
</span>

Pour aider avec l'accessibilité, j'ajoute même la valeur d'évaluation brute dans l'attribut title.

5
Tim Schmidt

en utilisant jquery sans prototype, mettez à jour le code js en 

$( ".stars" ).each(function() { 
    // Get the value
    var val = $(this).data("rating");
    // Make sure that the value is in 0 - 5 range, multiply to get width
    var size = Math.max(0, (Math.min(5, val))) * 16;
    // Create stars holder
    var $span = $('<span />').width(size);
    // Replace the numerical value with stars
    $(this).html($span);
});

J'ai également ajouté un attribut de données portant le nom data-rating dans la plage.

<span class="stars" data-rating="4" ></span>
4
Galuga

DEMO

Vous pouvez le faire avec 2 images seulement. 1 étoiles vides, 1 étoiles remplies.

Superposez l'image remplie sur le dessus de l'autre. et convertissez le nombre d'évaluation en pourcentage et utilisez-le comme largeur de l'image de remplissage.

 enter image description here

.containerdiv {
  border: 0;
  float: left;
  position: relative;
  width: 300px;
} 
.cornerimage {
  border: 0;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
 } 
 img{
   max-width: 300px;
 }
1
Elyor

Voici ce que je pense en utilisant JSX et une police géniale, limitée à une précision de .5 seulement, cependant:

       <span>
          {Array(Math.floor(rating)).fill(<i className="fa fa-star"></i>)}
          {(rating) - Math.floor(rating)==0 ? ('') : (<i className="fa fa-star-half"></i>)}
       </span>

La première rangée concerne l'étoile entière et la deuxième la demi-étoile (le cas échéant)

0
Ardhi