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

发布于 2024-08-16 04:15:56 字数 163 浏览 3 评论 0原文

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

九厘米的零° 2024-08-23 04:15:56

这是为您提供的一种解决方案,仅使用一张非常小且简单的图像和一个自动生成的 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;
}

Image

替代文本
(来源:ulmanen.fi

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

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

如果您想将星星限制为只有一半或四分之一星星大小,请在 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

<span class="stars">4.8618164</span>
<span class="stars">2.6545344</span>
<span class="stars">0.5355</span>
<span class="stars">8</span>

使用

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

输出

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

演示

http://www.ulmanen.fi/stuff/stars.php< /p>

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


关于星星如何呈现的一个小解释可能是合适的。

该脚本创建两个块级跨度元素。两个跨度最初的大小均为 80px * 16px,背景图像为 Stars.png。 Span 是嵌套的,因此 Span 的结构如下所示:

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

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

另一方面,内部跨度的 background-position0 0,这使得只有黄色星星可见。

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

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

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

在可访问性方面,明智的做法是将浮点数保留在内部范围内,并使用 text-indent: -9999px 隐藏它,这样关闭 CSS 的人至少可以看到浮点数字而不是星星。

希望这是有道理的。


更新时间:2010/10/22

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

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

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

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)

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

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 size row:

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>

Usage

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

Output

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

Demo

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:

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

The outer span gets a background-position of 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.

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

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.

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.

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.

Hopefully that made some sense.


Updated 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));
    });
}
橘虞初梦 2024-08-23 04:15:56

《纪元 2022》中有更多适用于现代浏览器的新方法,如果您可以在正确的位置生成评级/百分比,则需要更少的运行时代码。

让您的框架在正确的 style 位置生成此 html,例如 33.333% ,然后您就可以开始了:

.star-rating::before {
/* What also works: "⭐⭐⭐⭐⭐" or "

Anno 2022 there's more new methods available for modern browsers that require less runtime code if you can generate the rating/percentage in the right location.

Have your framework generate this html with e.g. 33.333% in the right style spots and you're good to go:

.star-rating::before {
  /* What also works: "⭐⭐⭐⭐⭐" or "????????????????????" or other characters. */
  content: "⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐";
}

.star-rating {
    display: inline-block;
    background-clip: text;
    -webkit-background-clip: text;
    color: rgba(0, 0, 0, 0.1);
}

body {
  font-size: 32px; /* for demo purpose */
}
<div
  class="star-rating"
  style="background-image: linear-gradient(
      to right,
      gold 0%,
      gold 33.333%,
      transparent 33.333%,
      transparent 100%);
  "
><!-- Don't forget to add an accessible alternative! --></div>


The original answer that accrued the first 40 upvotes then too:

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.

娇俏 2024-08-23 04:15:56

尝试这个 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>

Screenshot

Try this jquery helper function/file

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>

Screenshot

月竹挽风 2024-08-23 04:15:56

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

例如,4.8618164 乘以 4 并四舍五入为 19,即四又四分之三星。

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

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

记忆之渊 2024-08-23 04:15:56

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

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

为了帮助实现可访问性,我什至在标题属性中添加原始评级值。

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.

后eg是否自 2024-08-23 04:15:56

DEMO

您只需使用 2 张图片即可完成此操作。 1 个空白星星,1 个实心星星。

将填充的图像叠加在另一幅图像的顶部。并将评级数转换为百分比并将其用作填充图像的宽度。

输入图片此处描述

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

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;
 }
暖风昔人 2024-08-23 04:15:56

使用 CSS

  • background-clip 绘制 星星评级具有线性渐变背景的星号字符
  • CSS var()将评分值从模板传递到渐变图像百分比
[style^=--rating]::after {
  content: "★★★★★";
  font-size: 2em;
  white-space: nowrap;
  background: linear-gradient(90deg, #fb0 calc(var(--rating) * 20%), #ddd calc(var(--rating) * 20%));
  background-clip: text;
  -webkit-background-clip: text;
  color: #0000;
}
<span style="--rating:5.0"></span> <br>
<span style="--rating:1.7"></span> <br>
<span style="--rating:3.5"></span> <br>

为了实现可访问性,您还可以添加 Aria 属性,例如 aria-label="Rating: 4.5 star"


使用 CSS 和 JavaScript 进行星级评级

虽然上面的示例非常适合评级预览目的,但如果您想允许用户投票,则需要添加一些 JavaScript 来处理点击、UX 颜色指针交互的变化等 - 请参阅此相关答案:
带有指针事件的星级

Stars rating using CSS

  • background-clip to paint the star characters with a linear-gradient background
  • CSS var() to pass the rating value from the template to the gradient image percentage

[style^=--rating]::after {
  content: "★★★★★";
  font-size: 2em;
  white-space: nowrap;
  background: linear-gradient(90deg, #fb0 calc(var(--rating) * 20%), #ddd calc(var(--rating) * 20%));
  background-clip: text;
  -webkit-background-clip: text;
  color: #0000;
}
<span style="--rating:5.0"></span> <br>
<span style="--rating:1.7"></span> <br>
<span style="--rating:3.5"></span> <br>

For accessibility you can also add the Aria attribute like aria-label="Rating: 4.5 stars".


Stars rating using CSS and JavaScript

Whilst the above example is great for rating preview purpose, if you want to allow the user to cast a vote, you'll need to add some JavaScript for handling click, UX colors change on pointer interaction, etc. — See this related answer:
Star rating with pointer events

活雷疯 2024-08-23 04:15:56

使用没有原型的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);
});

我还在span中添加了一个名为data- rating的数据属性。

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

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>
北凤男飞 2024-08-23 04:15:56

这是我使用 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>

第一行是全星,第二行是半星(如果有的话)

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文