Zamień liczbę na wyświetlanie gwiazdek za pomocą jQuery i CSS

101

Patrzyłem na wtyczkę jquery i zastanawiałem się, jak dostosować tę wtyczkę, aby zamienić liczbę (na przykład 4,8618164) w 4,8618164 gwiazdki wypełnione z 5. Zasadniczo interpretowanie liczby <5 na gwiazdki wypełnione w 5-gwiazdkowym systemie ocen przy użyciu jQuery / JS / CSS.

Zwróć uwagę, że spowoduje to wyświetlenie / wyświetlenie oceny gwiazdek z już dostępnej liczby i nie akceptację nowych zgłoszeń ocen.

Steve
źródło

Odpowiedzi:

256

Oto rozwiązanie dla Ciebie, wykorzystujące tylko jeden bardzo mały i prosty obraz oraz jeden automatycznie generowany element span:

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

Wizerunek

tekst alternatywny
(źródło: ulmanen.fi )

Uwaga: nie NIE Hotlink na powyższy obrazek! Skopiuj plik na własny serwer i używaj go stamtąd.

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

Jeśli chcesz ograniczyć gwiazdy tylko do połowy lub ćwiartki gwiazd, dodaj jeden z tych wierszy przed var sizerzędem:

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>

Stosowanie

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

Wynik

Obraz z zestawu ikon fugi (www.pinvoke.com)
(źródło: ulmanen.fi )

Próbny

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

Prawdopodobnie będzie to odpowiadało Twoim potrzebom. Dzięki tej metodzie nie musisz obliczać żadnych trzech czwartych lub jakichkolwiek innych szerokości gwiazd, po prostu nadaj jej wartość zmienną, a otrzymasz swoje gwiazdy.


Krótkie wyjaśnienie, w jaki sposób są przedstawiane gwiazdy, może być w porządku.

Skrypt tworzy dwa elementy zakresu na poziomie bloku. Oba rozpiętości mają początkowo rozmiar 80px * 16px i obraz tła stars.png. Przęsła są zagnieżdżone, dzięki czemu struktura przęseł wygląda następująco:

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

Zewnętrzne przęsło ma wartość background-positionof 0 -16px. To sprawia, że ​​widoczne są szare gwiazdy na przęśle zewnętrznym. Ponieważ zewnętrzne przęsło ma wysokość 16 pikseli i repeat-xbędzie pokazywać tylko 5 szarych gwiazd.

Z drugiej strony wewnętrzna rozpiętość ma, background-positionz 0 0którego widoczne są tylko żółte gwiazdy.

To oczywiście działałoby z dwoma oddzielnymi plikami graficznymi, star_yellow.png i star_gray.png. Ale ponieważ gwiazdy mają stałą wysokość, możemy łatwo połączyć je w jeden obraz. Wykorzystuje to technikę sprite CSS .

Teraz, gdy przęsła są zagnieżdżone, są one automatycznie nakładane na siebie. W przypadku domyślnym, gdy szerokość obu rozpiętości wynosi 80 pikseli, żółte gwiazdy całkowicie zasłaniają szare gwiazdy.

Ale kiedy dostosujemy szerokość wewnętrznej rozpiętości, szerokość żółtych gwiazd zmniejsza się, odsłaniając szare gwiazdy.

Z text-indent: -9999pxpunktu widzenia dostępności rozsądniej byłoby pozostawić liczbę zmiennoprzecinkową wewnątrz wewnętrznej rozpiętości i ukryć ją za pomocą , tak aby osoby z wyłączonym CSS widziały przynajmniej liczbę zmiennoprzecinkową zamiast gwiazd.

Mam nadzieję, że to miało jakiś sens.


Zaktualizowano 2010/10/22

Teraz jeszcze bardziej kompaktowy i trudniejszy do zrozumienia! Można go również ścisnąć do jednej wkładki:

$.fn.stars = function() {
    return $(this).each(function() {
        $(this).html($('<span />').width(Math.max(0, (Math.min(5, parseFloat($(this).html())))) * 16));
    });
}
Tatu Ulmanen
źródło
@Tatu, jakakolwiek szansa na lepsze rozwinięcie tego, jak to działa. Moja wiedza o jQuery jest odrobinę krótka, aby ją w pełni zrozumieć. Myślę, że rozumiem, jak działa CSS z powtarzaniem w kierunku x i 16 * 5 = 80 bitów oraz jak dostosowujesz szerokość obrazu z żółtą gwiazdą, ale jak nakładasz dwa obrazy jeden na drugi z pojedynczy obraz, na którym jedna gwiazda znajduje się nad drugą? Czy -16px sprowadza szarą gwiazdę do tego samego poziomu co żółta?
paxdiablo
Dzięki za aktualizację, @Tatu, która ma teraz dla mnie dużo więcej sensu. Niestety dałem Ci już +1, więc nie mogę tego zrobić ponownie, ale mam nadzieję, że wyjaśnienie przyniesie Ci więcej (zasłużonych) rep. Twoje zdrowie.
paxdiablo
2
@paxdiablo i inni, dzięki za wsparcie. Może powinienem zrobić to właściwa jQuery Plugin w tej techniki wydaje się być zaskoczeniem dla większości :)
Tatu Ulmanen
@Tatu, wielkie dzięki. Wszystkie istniejące pięciogwiazdkowe wtyczki wydają się mieć formę, która jest odpowiednia do wprowadzania oceny, ale zbyt daleko idąca zmiana reprezentacji liczby.
vfilby
7
Lub jeszcze mniejszy: jsbin.com/IBIDalEn/2/edit (PS usunął niepotrzebne rzeczy w JS, zminimalizował selektory CSS i użył max-width).
Roko C. Buljan
30

Jeśli potrzebujesz tylko obsługi nowoczesnych przeglądarek, możesz uciec:

  • Brak obrazów;
  • Głównie statyczne css;
  • Prawie nie ma jQuery ani JavaScript;

Wystarczy przekonwertować numer na classnp class='stars-score-50'.

Najpierw demo „renderowanych” znaczników:

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>

Następnie demo, które używa odrobiny kodu:

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

Największe wady tego rozwiązania to:

  1. Potrzebujesz gwiazd wewnątrz elementu, aby wygenerować odpowiednią szerokość;
  2. Nie ma znaczników semantycznych, np. Wolisz partyturę jako tekst wewnątrz elementu;
  3. Pozwala tylko na tyle wyników, ile będziesz mieć klas (ponieważ nie możemy użyć Javascript do precyzyjnego widthustawienia pseudoelementu).

Aby to naprawić, powyższe rozwiązanie można łatwo zmienić. :beforei:after bity muszą stać się rzeczywiste elementy DOM (więc musimy trochę JS do tego).

Ten ostatni pozostawiamy jako ćwiczenie dla czytelnika.

Jeroen
źródło
3
Rozszerzyłem to rozwiązanie, aby uwzględnić zmiennoprzecinkowe i dynamicznie generowane wyniki, które nie mieszczą się w dziesiątych części 100. Codepen . Dzięki za rozpoczęcie: D
cameck
To całkiem słodki scenariusz
Nick Div,
1
Idealne rozwiązanie. Uczyniłeś mój dzień. Dzięki @Jeroen ... baw się dalej.
Prabhu Nandan Kumar
22

Wypróbuj tę funkcję / plik pomocnika 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>

Zrzut ekranu

Rajasekar D
źródło
Tylko uwaga, że ​​brakuje tagu zamykającego </script> :)
Rob Stocki,
7

Dlaczego nie mieć po prostu pięciu oddzielnych obrazów gwiazdy (pustych, w jednej czwartej, w połowie, w trzech czwartych i pełne), a następnie po prostu wstrzyknąć obrazy do swojego DOM w zależności od obciętej lub zaokrąglonej wartości oceny pomnożonej przez 4 ( uzyskać liczbę całkowitą za ćwiartki)?

Na przykład 4,8618164 pomnożone przez 4 i zaokrąglone to 19, co oznaczałoby cztery i trzy czwarte gwiazdy.

Alternatywnie (jeśli jesteś leniwy jak ja), po prostu wybierz jeden obraz z 21 (od 0 do 5 gwiazdek w odstępach co jedną czwartą) i wybierz pojedynczy obraz na podstawie wspomnianej wartości. Wtedy to tylko jedno obliczenie, po którym następuje zmiana obrazu w DOM (zamiast próby zmiany pięciu różnych obrazów).

paxdiablo
źródło
5

Skończyło się na tym, że całkowicie uwolniłem się od JS, aby uniknąć opóźnień renderowania po stronie klienta. Aby to osiągnąć, generuję HTML w następujący sposób:

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

Aby pomóc w ułatwieniu dostępu, dodaję nawet surową wartość oceny w atrybucie tytułu.

Tim Schmidt
źródło
4

używając jquery bez prototypu, zaktualizuj kod js do

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

Dodałem również atrybut danych o nazwie ocena danych w zakresie.

<span class="stars" data-rating="4" ></span>
Galuga
źródło
3

PRÓBNY

Możesz to zrobić tylko z 2 obrazami. 1 puste gwiazdki, 1 wypełnione gwiazdki.

Nałóż wypełniony obraz na drugi. i zamień ocenę na procent i użyj jej jako szerokości obrazka wypełniającego.

wprowadź opis obrazu tutaj

.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
źródło
0

Oto moje spojrzenie na użycie JSX i niesamowitych czcionek, jednak ograniczone tylko do dokładności 0,5:

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

Pierwszy rząd dotyczy całej gwiazdy, a drugi pół gwiazdki (jeśli występuje)

Ardhi
źródło