Trasforma un numero nella visualizzazione della valutazione a stelle utilizzando jQuery e CSS


101

Ho esaminato il plugin jquery e mi chiedevo come adattare quel plugin per trasformare un numero (come 4.8618164) in 4.8618164 stelle compilate su 5. Fondamentalmente interpretando un numero <5 in stelle compilate in un sistema di valutazione a 5 stelle usando jQuery / JS / CSS.

Tieni presente che questo mostrerà / mostrerà solo la valutazione delle stelle da un numero già disponibile e non accetterà l'invio di nuove valutazioni.


Risposte:


255

Ecco una soluzione per te, utilizzando solo un'immagine molto piccola e semplice e un elemento span generato automaticamente:

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;
}

Immagine

testo alternativo
(fonte: ulmanen.fi )

Nota: non non hotlink per l'immagine qui sopra! Copia il file sul tuo server e usalo da 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);
    });
}

Se desideri limitare le dimensioni delle stelle solo a metà o un quarto di stella, aggiungi una di queste righe prima della var sizeriga:

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>

uso

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

Produzione

Immagine dal set di icone della fuga (www.pinvoke.com)
(fonte: ulmanen.fi )

dimostrazione

http://www.ulmanen.fi/stuff/stars.php

Questo probabilmente soddisferà le tue esigenze. Con questo metodo non devi calcolare tre quarti o quant'altro della larghezza delle stelle, basta dargli un galleggiante e ti darà le tue stelle.


Una piccola spiegazione su come vengono presentate le stelle potrebbe essere in ordine.

Lo script crea due elementi span a livello di blocco. Entrambi gli intervalli ottengono inizialmente una dimensione di 80px * 16px e un'immagine di sfondo stars.png. Le campate sono nidificate, in modo che la struttura delle campate assomigli a questa:

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

L'estensione esterna diventa background-positiondi 0 -16px. Ciò rende visibili le stelle grigie nella campata esterna. Poiché l'estensione esterna ha un'altezza di 16 px e repeat-x, mostrerà solo 5 stelle grigie.

La campata interna invece ha una background-positiondi 0 0cui sono visibili solo le stelle gialle.

Questo ovviamente funzionerebbe con due file immagine separati, star_yellow.png e star_gray.png. Ma poiché le stelle hanno un'altezza fissa, possiamo facilmente combinarle in un'unica immagine. Questo utilizza la tecnica dello sprite CSS .

Ora, poiché le campate sono nidificate, vengono automaticamente sovrapposte l'una sull'altra. Nel caso predefinito, quando la larghezza di entrambe le campate è 80px, le stelle gialle oscurano completamente le stelle grigie.

Ma quando regoliamo la larghezza della campata interna, la larghezza delle stelle gialle diminuisce, rivelando le stelle grigie.

Dal punto di vista dell'accessibilità, sarebbe stato più saggio lasciare il numero float all'interno dell'intervallo interno e nasconderlo text-indent: -9999px, in modo che le persone con CSS disattivato vedessero almeno il numero in virgola mobile invece delle stelle.

Si spera che avesse un senso.


Aggiornato il 22/10/2010

Ora ancora più compatto e più difficile da capire! Può anche essere ridotto a un rivestimento:

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

@Tatu, ogni possibilità di arricchirlo un po 'di più con come funziona. La mia conoscenza di jQuery è solo un po 'breve per ottenerla totalmente. Penso di capire come funziona il CSS con la ripetizione nella direzione x e 16 * 5 = 80 bit e come si regola la larghezza dell'immagine della stella gialla, ma come stai sovrapponendo le due immagini una sopra l'altra da un singola immagine che ha una stella sopra l'altra? Il -16px porta la stella grigia allo stesso livello del giallo?
paxdiablo

Grazie per l'aggiornamento, @Tatu, per me ora ha molto più senso. Sfortunatamente ti avevo già dato un +1, quindi non posso farlo di nuovo, ma spero che la spiegazione ti faccia guadagnare un po 'di più (meritata) reputazione. Saluti.
paxdiablo

2
@paxdiablo e altri, grazie per il supporto. Forse dovrei renderlo un plugin jQuery appropriato poiché questa tecnica sembra essere una sorpresa per la maggior parte :)
Tatu Ulmanen

@Tatu, grazie immensamente. I plug-in a cinque stelle esistenti sembrano tutti volere un modulo che vada bene per l'inserimento di una valutazione, ma in modo eccessivo per cambiare la rappresentazione di un numero.
vfilby

7
O ancora più piccolo: jsbin.com/IBIDalEn/2/edit (PS ha rimosso cose non necessarie in JS, selettori CSS minimizzati e usati max-width).
Roko C. Buljan

30

Se devi supportare solo i browser moderni, puoi cavartela con:

  • Nessuna immagine;
  • Per lo più CSS statico;
  • Quasi nessun jQuery o Javascript;

Hai solo bisogno di convertire il numero in un class, ad es class='stars-score-50'.

Prima una demo del markup "renderizzato":

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>

Quindi una demo che utilizza un po 'di codice:

$(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>

I maggiori svantaggi di questa soluzione sono:

  1. Hai bisogno delle stelle all'interno dell'elemento per generare la larghezza corretta;
  2. Non c'è marcatura semantica, ad esempio preferiresti la partitura come testo all'interno dell'elemento;
  3. Permette solo tanti punteggi quante sono le classi (perché non possiamo usare Javascript per impostare un preciso widthsu uno pseudo-elemento).

Per risolvere questo problema, la soluzione sopra può essere facilmente modificata. I bit :beforee :afterdevono diventare elementi effettivi nel DOM (quindi abbiamo bisogno di un po 'di JS per questo).

Quest'ultimo è lasciato come esercizio per il lettore.


3
Ho esteso questa soluzione per accogliere i float e le partiture generate dinamicamente che non si adattano ai decimi di 100. Codepen . Grazie per avermi fatto iniziare: D
cameck

Questa è una sceneggiatura piuttosto dolce
Nick Div

1
Soluzione perfetta. Hai reso la mia giornata. Grazie @ Jeroen ... continua a dondolare.
Prabhu Nandan Kumar

22

Prova questa funzione / file di supporto jquery

jquery.Rating.js

//ES5
$.fn.stars = function() {
    return $(this).each(function() {
        var rating = $(this).data("rating");
        var fullStar = new Array(Math.floor(rating + 1)).join('<i class="fas fa-star"></i>');
        var halfStar = ((rating%1) !== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
        var noStar = new Array(Math.floor($(this).data("numStars") + 1 - rating)).join('<i class="far fa-star"></i>');
        $(this).html(fullStar + halfStar + noStar);
    });
}

//ES6
$.fn.stars = function() {
    return $(this).each(function() {
        const rating = $(this).data("rating");
        const numStars = $(this).data("numStars");
        const fullStar = '<i class="fas fa-star"></i>'.repeat(Math.floor(rating));
        const halfStar = (rating%1!== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
        const noStar = '<i class="far fa-star"></i>'.repeat(Math.floor(numStars-rating));
        $(this).html(`${fullStar}${halfStar}${noStar}`);
    });
}

index.html

   <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Star Rating</title>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <script src="js/jquery.Rating.js"></script>
        <script>
            $(function(){
                $('.stars').stars();
            });
        </script>
    </head>
    <body>

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

    </body>
    </html>

Immagine dello schermo


Solo una nota che manca il tag </script> di chiusura :)
Rob Stocki

7

Perché non avere solo cinque immagini separate di una stella (vuota, piena per un quarto, mezza piena, piena per tre quarti e piena) e poi inserisci semplicemente le immagini nel tuo DOM a seconda del valore troncato o arrotondato della valutazione moltiplicato per 4 ( per ottenere un intero numero per i quarti)?

Ad esempio, 4,8618164 moltiplicato per 4 e arrotondato è 19, che sarebbe quattro stelle e tre quarti.

In alternativa (se sei pigro come me), seleziona solo un'immagine da 21 (da 0 stelle a 5 stelle con incrementi di un quarto) e seleziona la singola immagine in base al valore di cui sopra. Quindi è solo un calcolo seguito da un cambio di immagine nel DOM (invece di provare a cambiare cinque immagini diverse).


5

Ho finito per essere totalmente privo di JS per evitare ritardi di rendering lato client. Per fare ciò, genero HTML in questo modo:

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

Per aiutare con l'accessibilità, aggiungo persino il valore di valutazione grezzo nell'attributo del titolo.


4

usando jquery senza prototipo, aggiorna il codice js a

$( ".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);
});

Ho anche aggiunto un attributo di dati con il nome di classificazione dei dati nell'intervallo.

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

2

DEMO

Puoi farlo solo con 2 immagini. 1 stella vuota, 1 stella piena.

Sovrapponi l'immagine piena sopra l'altra. e converti il ​​numero di valutazione in percentuale e usalo come larghezza dell'immagine di riempimento.

inserisci qui la descrizione dell'immagine

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

0

Ecco la mia opinione sull'uso di JSX e di caratteri fantastici, limitati solo alla precisione.

       <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 prima riga è per l'intera stella e la seconda riga è per la mezza stella (se presente)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.