Verwandeln Sie eine Zahl mit jQuery und CSS in eine Sternebewertung

101

Ich habe mir das jquery-Plugin angesehen und mich gefragt, wie ich dieses Plugin anpassen kann, um aus einer Zahl (wie 4.8618164) eine 4.8618164 von 5 ausgefüllten Sterne zu machen. Grundsätzlich wird eine Zahl <5 in Sterne interpretiert, die in einem 5-Sterne-Bewertungssystem mit jQuery ausgefüllt sind / JS / CSS.

Beachten Sie, dass dies nur die Sternebewertung einer bereits verfügbaren Nummer anzeigt / anzeigt und keine neuen Bewertungsbeiträge akzeptiert.

Steve
quelle

Antworten:

255

Hier ist eine Lösung für Sie, bei der nur ein sehr kleines und einfaches Bild und ein automatisch generiertes Span-Element verwendet werden:

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

Bild

Alt-Text
(Quelle: ulmanen.fi )

Hinweis: Sie NICHT hotlink das obige Bild! Kopieren Sie die Datei auf Ihren eigenen Server und verwenden Sie sie von dort aus.

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

Wenn Sie die Sterne auf nur halbe oder viertel Sterngrößen beschränken möchten, fügen Sie vor der var sizeZeile eine dieser Zeilen hinzu :

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>

Verwendung

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

Ausgabe

Bild vom Fugensymbolsatz (www.pinvoke.com)
(Quelle: ulmanen.fi )

Demo

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

Dies wird wahrscheinlich Ihren Bedürfnissen entsprechen. Mit dieser Methode müssen Sie keine Dreiviertel- oder andere Sternbreiten berechnen. Geben Sie einfach einen Float und Sie erhalten Ihre Sterne.


Eine kleine Erklärung, wie die Sterne dargestellt werden, könnte angebracht sein.

Das Skript erstellt zwei Span-Elemente auf Blockebene. Beide Bereiche erhalten zunächst eine Größe von 80px * 16px und ein Hintergrundbild stars.png. Die Bereiche sind verschachtelt, sodass die Struktur der Bereiche folgendermaßen aussieht:

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

Die äußere Spannweite erhält eine background-positionvon 0 -16px. Das macht die grauen Sterne in der äußeren Spanne sichtbar. Da die äußere Spannweite eine Höhe von 16 Pixel hat und repeat-xnur 5 graue Sterne angezeigt werden.

Die innere Spannweite hat dagegen eine, background-positionvon 0 0der nur die gelben Sterne sichtbar sind.

Dies würde natürlich mit zwei separaten Bilddateien funktionieren, star_yellow.png und star_gray.png. Da die Sterne jedoch eine feste Höhe haben, können wir sie leicht zu einem Bild kombinieren. Dies nutzt die CSS-Sprite-Technik .

Wenn die Bereiche verschachtelt sind, werden sie automatisch übereinander gelegt. Im Standardfall, wenn die Breite beider Bereiche 80 Pixel beträgt, verdecken die gelben Sterne die grauen Sterne vollständig.

Wenn wir jedoch die Breite der inneren Spanne anpassen, nimmt die Breite der gelben Sterne ab und zeigt die grauen Sterne.

In Bezug auf die Barrierefreiheit wäre es klüger gewesen, text-indent: -9999pxdie Gleitkommazahl innerhalb der inneren Spanne zu belassen und mit auszublenden , damit Personen mit deaktiviertem CSS zumindest die Gleitkommazahl anstelle der Sterne sehen.

Hoffentlich machte das Sinn.


Aktualisiert am 22.10.2010

Jetzt noch kompakter und schwerer zu verstehen! Kann auch zu einem Einzeiler zusammengedrückt werden:

$.fn.stars = function() {
    return $(this).each(function() {
        $(this).html($('<span />').width(Math.max(0, (Math.min(5, parseFloat($(this).html())))) * 16));
    });
}
Tatu Ulmanen
quelle
@Tatu, jede Chance, es ein bisschen mehr zu konkretisieren, wie das funktioniert. Mein Wissen über jQuery ist nur ein bisschen kurz, um es vollständig zu verstehen. Ich denke, ich verstehe, wie das CSS mit Wiederholungen in x-Richtung und 16 * 5 = 80 Bit funktioniert und wie Sie die Breite des Gelbsternbildes anpassen, aber wie überlagern Sie die beiden Bilder von a übereinander Einzelbild mit einem Stern über dem anderen? Bringt der -16px den grauen Stern auf das gleiche Niveau wie den gelben?
Paxdiablo
Danke für das Update, @Tatu, das macht für mich jetzt viel mehr Sinn. Leider hatte ich dir bereits +1 gegeben, so dass ich es nicht noch einmal machen kann, aber hoffentlich bringt dir die Erklärung mehr (wohlverdiente) Wiederholungen ein. Prost.
Paxdiablo
2
@paxdiablo und andere, danke für die Unterstützung. Vielleicht sollte ich dies zu einem richtigen jQuery-Plugin machen, da diese Technik für die meisten überraschend zu sein scheint :)
Tatu Ulmanen
@Tatu, vielen Dank. Die vorhandenen Fünf-Sterne-Plugins scheinen alle ein Formular zu wollen, das für die Eingabe einer Bewertung in Ordnung ist, aber viel zu viel, um die Darstellung einer Zahl zu ändern.
Vfilby
7
Oder noch kleiner: jsbin.com/IBIDalEn/2/edit (PS hat nicht benötigtes Material in JS entfernt, CSS-Selektoren minimiert und verwendet max-width).
Roko C. Buljan
30

Wenn Sie nur moderne Browser unterstützen müssen, können Sie Folgendes tun:

  • Keine Bilder;
  • Meist statische CSS;
  • Fast kein jQuery oder Javascript;

Sie müssen nur die Zahl in a umwandeln class, z class='stars-score-50'.

Zuerst eine Demo von "gerendertem" Markup:

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>

Dann eine Demo, die ein bisschen Code verwendet:

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

Die größten Nachteile dieser Lösung sind:

  1. Sie benötigen die Sterne im Element, um die richtige Breite zu erzeugen.
  2. Es gibt kein semantisches Markup, z. B. würden Sie die Partitur als Text innerhalb des Elements bevorzugen .
  3. Es werden nur so viele Partituren zugelassen, wie Sie Klassen haben (da wir kein Javascript verwenden können, um eine Genauigkeit widthfür ein Pseudoelement festzulegen).

Um dies zu beheben, kann die obige Lösung leicht angepasst werden. Die :beforeund :afterBits müssen zu tatsächlichen Elementen im DOM werden (daher benötigen wir dafür JS).

Letzteres bleibt als Übung für den Leser.

Jeroen
quelle
3
Ich habe diese Lösung erweitert, um Floats und dynamisch generierte Scores zu berücksichtigen , die nicht in Zehntel einer 100 passen . Codepen . Vielen Dank für den Einstieg: D
Cameck
Dies ist ein ziemlich süßes Drehbuch
Nick Div
1
Perfekte Lösung. Du hast meinen Tag gerettet . Danke @Jeroen ... rock weiter.
Prabhu Nandan Kumar
22

Probieren Sie diese jquery-Hilfsfunktion / -datei aus

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>

Bildschirmfoto

Rajasekar D.
quelle
Nur eine Anmerkung, dass das schließende </ script> -Tag fehlt :)
Rob Stocki
7

Warum nicht einfach fünf separate Bilder eines Sterns (leer, viertelvoll, halbvoll, dreiviertelvoll und voll) haben und die Bilder dann einfach in Ihr DOM einfügen, abhängig vom abgeschnittenen oder gerundeten Wert der Bewertung multipliziert mit 4 ( eine ganze Zahl für die Quartale bekommen)?

Zum Beispiel ist 4.8618164 multipliziert mit 4 und gerundet 19, was vier und drei Viertelsterne wäre.

Alternativ (wenn Sie faul sind wie ich) können Sie einfach ein Bild aus 21 auswählen (0 Sterne bis 5 Sterne in Schritten von einem Viertel) und das einzelne Bild basierend auf dem oben genannten Wert auswählen. Dann ist es nur eine Berechnung, gefolgt von einer Bildänderung im DOM (anstatt zu versuchen, fünf verschiedene Bilder zu ändern).

paxdiablo
quelle
5

Am Ende war ich völlig JS-frei, um clientseitige Renderverzögerungen zu vermeiden. Um dies zu erreichen, generiere ich HTML wie folgt:

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

Um die Barrierefreiheit zu verbessern, füge ich sogar den Rohbewertungswert in das title-Attribut ein.

Tim Schmidt
quelle
4

Aktualisieren Sie mit jquery ohne Prototyp den js-Code auf

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

Ich habe auch ein Datenattribut mit dem Namen der Datenbewertung in der Spanne hinzugefügt.

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

DEMO

Sie können dies nur mit 2 Bildern tun. 1 leere Sterne, 1 gefüllte Sterne.

Überlagern Sie das gefüllte Bild oben auf dem anderen. und konvertieren Sie die Bewertungszahl in Prozent und verwenden Sie sie als Breite des Füllbildes.

Geben Sie hier die Bildbeschreibung ein

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

Hier ist meine Einstellung zur Verwendung von JSX und einer fantastischen Schriftart, die jedoch auf eine Genauigkeit von nur 0,5 beschränkt ist:

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

Die erste Reihe ist für den ganzen Stern und die zweite Reihe ist für den halben Stern (falls vorhanden)

Ardhi
quelle