Javascript 使用 jQuery 和 CSS 将数字转换为星级显示

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1987524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 22:15:34  来源:igfitidea点击:

Turn a number into star rating display using jQuery and CSS

javascriptjquerycssrating

提问by Steve

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.

我一直在看 jquery 插件,想知道如何调整该插件以将数字(如 4.8618164)转换为 4.8618164 颗星,满分为 5。基本上使用 jQuery 将小于 5 的数字解释为 5 星评级系统中的星/JS/CSS。

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

请注意,这只会显示/显示现有数字中的星级评分,并且不接受新的评分提交。

回答by Tatu Ulmanen

Here's a solution for you, using only one very tiny and simple image and one automatically generated span element:

这是一个适合您的解决方案,仅使用一个非常小而简单的图像和一个自动生成的 span 元素:

CSS

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
(source: ulmanen.fi)

替代文字
(来源:ulmanen.fi

Note:do NOThotlink to the above image! Copy the file to your own server and use it from there.

注意:千万不要热链接上面的图像!将文件复制到您自己的服务器并从那里使用它。

jQuery

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

If you want to restrict the stars to only half or quarter star sizes, add one of these rows before the var sizerow:

如果您想将星星限制为只有一半或四分之一的星星大小,请在该行之前添加以下行之一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

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

Output

输出

Image from fugue icon set (www.pinvoke.com)
(source: ulmanen.fi)

图片来自赋格图标集 (www.pinvoke.com)
(来源:ulmanen.fi

Demo

演示

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

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

This will probably suit your needs. With this method you don't have to calculate any three quarter or whatnot star widths, just give it a float and it'll give you your stars.

这可能会满足您的需求。使用这种方法,您不必计算任何四分之三或诸如此类的星星宽度,只需给它一个浮点数,它就会为您提供星星。



A small explanation on how the stars are presented might be in order.

关于如何呈现星星的小解释可能是有序的。

The script creates two block level span elements. Both of the spans initally get a size of 80px * 16px and a background image stars.png. The spans are nested, so that the structure of the spans looks like this:

该脚本创建两个块级跨度元素。两个跨度最初都获得了 80px * 16px 的大小和一个背景图像 stars.png。跨度是嵌套的,因此跨度的结构如下所示:

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

The outer span gets a background-positionof 0 -16px. That makes the gray stars in the outer span visible. As the outer span has height of 16px and repeat-x, it will only show 5 gray stars.

外跨度得到了background-position0 -16px。这使得外跨度中的灰色星星可见。由于外跨度的高度为 16px 和repeat-x,因此它只会显示 5 颗灰色星星。

The inner span on the other hand has a background-positionof 0 0which makes only the yellow stars visible.

在另一方面内宽度具有background-position0 0,这使得只有黄色星星可见。

This would of course work with two separate imagefiles, star_yellow.png and star_gray.png. But as the stars have a fixed height, we can easily combine them into one image. This utilizes the CSS sprite technique.

这当然适用于两个单独的图像文件,star_yellow.png 和 star_gray.png。但是由于星星的高度是固定的,我们可以很容易地将它们组合成一个图像。这利用了CSS 精灵技术

Now, as the spans are nested, they are automatically overlayed over each other. In the default case, when the width of both spans is 80px, the yellow stars completely obscure the grey stars.

现在,由于跨度是嵌套的,它们会自动相互重叠。默认情况下,当两个跨度的宽度为 80px 时,黄色的星星完全遮住了灰色的星星。

But when we adjust the width of the inner span, the width of the yellow stars decreases, revealing the gray stars.

但是当我们调整内部跨度的宽度时,黄色星星的宽度减小,露出灰色星星。

Accessibility-wise, it would have been wiser to leave the float number inside the inner span and hide it with text-indent: -9999px, so that people with CSS turned off would at least see the floating point number instead of the stars.

在可访问性方面,将浮点数留在内部跨度内并用 隐藏它会更明智text-indent: -9999px,这样关闭 CSS 的人至少会看到浮点数而不是星星。

Hopefully that made some sense.

希望这是有道理的。



Updated 2010/10/22

2010/10/22 更新

Now even more compact and harder to understand! Can also be squeezed down to a one liner:

现在更紧凑,更难理解!也可以压缩成一个内衬:

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

回答by Jeroen

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

如果您只需要支持现代浏览器,您可以使用:

  • Noimages;
  • Mostlystatic css;
  • Nearlyno jQuery or Javascript;
  • 没有图像;
  • 主要是静态 css;
  • 几乎没有 jQuery 或 Javascript;

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

您只需要将数字转换为 a class,例如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 scoreas text inside the element;
  3. It only allows for as many scores as you'll have classes (because we can'tuse Javascript to set a precise widthon a pseudo-element).
  1. 您需要元素内的星星来生成正确的宽度;
  2. 没有语义标记,例如,您更喜欢将分数作为元素内的文本;
  3. 它只允许与您拥有的类一样多的分数(因为我们不能使用 Javascript 对width伪元素进行精确设置)。

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

要解决此问题,可以轻松调整上述解决方案。在:before:after位需要成为DOM实际元素(所以我们需要一些JS为)。

The latter is left as an excercise for the reader.

后者留给读者作为练习。

回答by Rajasekar D

Try this jquery helper function/file

试试这个 jquery 辅助函数/文件

jquery.Rating.js

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

索引.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>

Screenshot

截屏

回答by paxdiablo

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

为什么不只拥有五张单独的星星图像(空、四分之一满、半满、四分之三满和满),然后根据截断或粗略的评级值乘以 4 将图像注入 DOM(获得四分之一的整数)?

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

例如,4.8618164 乘以 4 并四舍五入是 19,这将是四分之三星。

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

或者(如果您像我一样懒惰),只需从 21 个图像(0 星到 5 星,以四分之一为增量)中选择一张图像,然后根据上述值选择单个图像。然后它只是一个计算,然后在 DOM 中更改图像(而不是尝试更改五个不同的图像)。

回答by Tim Schmidt

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

我最终完全不使用 JS 以避免客户端渲染延迟。为了实现这一点,我生成了这样的 HTML:

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

为了提高可访问性,我什至在 title 属性中添加了原始评分值。

回答by Galuga

using jquery without prototype, update the js code to

使用没有原型的jquery,将js代码更新为

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

回答by Elyor

DEMO

演示

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

您只能使用 2 张图像来完成。1 颗空星,1 颗实心星。

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

回答by Ardhi

Here's my take using JSX and font awesome, limited on only .5 accuracy, though:

这是我使用 JSX 和字体真棒的看法,但仅限于 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>

First row is for whole star and second row is for half star (if any)

第一排是整星,第二排是半星(如果有的话)