Turn a number into star rating display using jQuer

2019-01-01 14:02发布

I have been looking at jquery plugin and was wondering how to adapt that plugin to turn a number (like 4.8618164) into a 4.8618164 stars filled out of 5. Basically interpreting a number <5 into stars filled in a 5-star rating system using jQuery/JS/CSS.

Note that this would only display/show the stars rating from an already available number and not accept new ratings submissions.

7条回答
余欢
2楼-- · 2019-01-01 14:29

Try this jquery function

<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

You can download FontAwesome at http://fontawesome.io/

查看更多
弹指情弦暗扣
3楼-- · 2019-01-01 14:32

DEMO

You can do it with 2 images only. 1 blank stars, 1 filled stars.

Overlay filled image on the top of the other one. and convert rating number into percentage and use it as width of fillter image.

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;
 }
查看更多
时光乱了年华
4楼-- · 2019-01-01 14:38

Why not just have five separate images of a star (empty, quarter-full, half-full, three-quarter-full and full) then just inject the images into your DOM depending on the truncated or rouded value of rating multiplied by 4 (to get a whole numner for the quarters)?

For example, 4.8618164 multiplied by 4 and rounded is 19 which would be four and three quarter stars.

Alternatively (if you're lazy like me), just have one image selected from 21 (0 stars through 5 stars in one-quarter increments) and select the single image based on the aforementioned value. Then it's just one calculation followed by an image change in the DOM (rather than trying to change five different images).

查看更多
与风俱净
5楼-- · 2019-01-01 14:41

I ended up going totally JS-free to avoid client-side render lag. To accomplish that, I generate HTML like this:

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

To help with accessibility, I even add the raw rating value in the title attribute.

查看更多
与风俱净
6楼-- · 2019-01-01 14:47

using jquery without prototype, update the js code to

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

I also added a data attribute by the name of data-rating in the span.

<span class="stars" data-rating="4" ></span>
查看更多
梦寄多情
7楼-- · 2019-01-01 14:54

If you only have to support modern browsers, you can get away with:

  • No images;
  • Mostly static css;
  • Nearly no jQuery or Javascript;

You only need to convert the number to a class, e.g. class='stars-score-50'.

First a demo of "rendered" 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>

Then a demo that uses a wee bit of 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>

The biggest downsides of this solution are:

  1. You need the stars inside the element to generate correct width;
  2. There's no semantic markup, e.g. you'd prefer the score as text inside the element;
  3. It only allows for as many scores as you'll have classes (because we can't use Javascript to set a precise width on a pseudo-element).

To fix this the solution above can be easily tweaked. The :before and :after bits need to become actual elements in the DOM (so we need some JS for that).

The latter is left as an excercise for the reader.

查看更多
登录 后发表回答